removed erronousely copied directory

pull/183/head
David Michaeli 2024-01-31 17:57:16 +02:00
rodzic f98c85d732
commit 1d7df81f5f
811 zmienionych plików z 0 dodań i 112637 usunięć

Wyświetl plik

@ -1 +0,0 @@
build

Wyświetl plik

@ -1,155 +0,0 @@
cmake_minimum_required(VERSION 3.15)
project(cariboulite
VERSION 1.2.0
LANGUAGES C CXX
DESCRIPTION "CaribouLite RpiSDR C API")
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Bring the headers
include_directories(./src)
include_directories(${PROJECT_SOURCE_DIR}/src)
add_compile_options(-Wall -Wextra -Wno-unused-variable -Wno-missing-braces)
# ------------------------------------
# MAIN - Source files for main library
# ------------------------------------
set(SOURCES_LIB src/cariboulite.c src/cariboulite_setup.c src/cariboulite_events.c src/cariboulite_radio.c)
set(TARGET_LINK_LIBS datatypes
production_utils
caribou_fpga
at86rf215
rffc507x
caribou_smi
caribou_prog
hat
io_utils
zf_log
rt
m
pthread)
set(SOURCES_CPP_LIB src/CaribouLiteCpp.cpp src/CaribouLiteRadioCpp.cpp)
# Add internal project dependencies
add_subdirectory(src/datatypes EXCLUDE_FROM_ALL)
add_subdirectory(src/caribou_programming EXCLUDE_FROM_ALL)
add_subdirectory(src/caribou_fpga EXCLUDE_FROM_ALL)
add_subdirectory(src/at86rf215 EXCLUDE_FROM_ALL)
add_subdirectory(src/caribou_smi EXCLUDE_FROM_ALL)
add_subdirectory(src/io_utils EXCLUDE_FROM_ALL)
add_subdirectory(src/rffc507x EXCLUDE_FROM_ALL)
add_subdirectory(src/hat EXCLUDE_FROM_ALL)
add_subdirectory(src/production_utils EXCLUDE_FROM_ALL)
add_subdirectory(src/zf_log EXCLUDE_FROM_ALL)
add_subdirectory(src/iir EXCLUDE_FROM_ALL)
# Create the library cariboulite
add_library(cariboulite STATIC ${SOURCES_LIB} ${SOURCES_CPP_LIB})
target_link_libraries(cariboulite PRIVATE ${TARGET_LINK_LIBS})
set_target_properties(cariboulite PROPERTIES PUBLIC_HEADER "src/cariboulite.h;src/cariboulite_radio.h;src/CaribouLite.hpp")
set_target_properties(cariboulite PROPERTIES OUTPUT_NAME cariboulite)
add_library(cariboulite_shared SHARED ${SOURCES_LIB} ${SOURCES_CPP_LIB})
target_link_libraries(cariboulite_shared PRIVATE ${TARGET_LINK_LIBS})
set_target_properties(cariboulite_shared PROPERTIES PUBLIC_HEADER "src/cariboulite.h;src/cariboulite_radio.h;src/CaribouLite.hpp")
set_property(TARGET cariboulite_shared PROPERTY POSITION_INDEPENDENT_CODE 1)
set_target_properties(cariboulite_shared PROPERTIES OUTPUT_NAME cariboulite)
#--------------------------------------
# create the Soapy shared object
#--------------------------------------
find_package(SoapySDR CONFIG)
if (NOT SoapySDR_FOUND)
message(WARNING "SoapySDR development files not found - skipping support")
return()
endif ()
if(CMAKE_COMPILER_IS_GNUCXX)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" HAS_STD_CXX11)
if(HAS_STD_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3")
else(HAS_STD_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -O3")
endif()
#Thread support enabled (not the same as -lpthread)
list(APPEND SOAPY_CARIBOULITE_LIBRARIES)
add_definitions(-Wno-unused-parameter -Wno-missing-field-initializers -Wno-parentheses -Wno-psabi)
endif(CMAKE_COMPILER_IS_GNUCXX)
execute_process (
COMMAND bash -c "SoapySDRUtil --info | grep 'Search path' | cut -d':' -f2 | xargs | cut -d' ' -f1 | xargs"
OUTPUT_VARIABLE SOAPY_DEST
)
string(STRIP ${SOAPY_DEST} SOAPY_DEST)
execute_process (
COMMAND bash -c "SoapySDRUtil --info | grep 'Search path' | cut -d':' -f2 | xargs | cut -d' ' -f1 | awk -F '/lib/' '{print $1}' | xargs"
OUTPUT_VARIABLE BIN_DEST
)
string(STRIP ${BIN_DEST} BIN_DEST)
SOAPY_SDR_MODULE_UTIL(
TARGET SoapyCariboulite
SOURCES
src/soapy_api/SoapyCariboulite.cpp
src/soapy_api/Cariboulite.cpp
src/soapy_api/Cariboulite.hpp
src/soapy_api/CaribouliteStreamFunctions.cpp
src/soapy_api/CaribouliteStream.cpp
src/soapy_api/CaribouliteSession.cpp
src/soapy_api/CaribouliteSensors.cpp
LIBRARIES cariboulite iir
DESTINATION ${SOAPY_DEST}
PREFIX ""
)
# ----------------------------------
# TESTS - source files for the tests
# ----------------------------------
set(SOURCES_CARIBOU_PROGRAMMER test/caribou_programmer.c)
set(SOURCES_FPGA_COMM test/fpga_comm_test.c)
set(SOURCES_TEST_MAIN src/cariboulite_test_app.c src/app_menu.c)
set(SOURCES_MAIN src/cariboulite_util.c)
set(SOURCES_PROD src/cariboulite_production.c)
add_executable(caribou_programmer ${SOURCES_CARIBOU_PROGRAMMER})
add_executable(fpgacomm ${SOURCES_FPGA_COMM})
add_executable(cariboulite_test_app ${SOURCES_TEST_MAIN})
add_executable(cariboulite_util ${SOURCES_MAIN})
target_link_libraries(caribou_programmer cariboulite)
target_link_libraries(fpgacomm cariboulite)
target_link_libraries(cariboulite_test_app cariboulite)
target_link_libraries(cariboulite_util cariboulite)
set_target_properties( caribou_programmer PROPERTIES RUNTIME_OUTPUT_DIRECTORY test)
set_target_properties( fpgacomm PROPERTIES RUNTIME_OUTPUT_DIRECTORY test)
# ------------
# INSTALLATION
# ------------
install(TARGETS cariboulite
LIBRARY DESTINATION ${BIN_DEST}/lib/
ARCHIVE DESTINATION ${BIN_DEST}/lib/
PUBLIC_HEADER DESTINATION ${BIN_DEST}/include/)
install(TARGETS cariboulite_shared
LIBRARY DESTINATION ${BIN_DEST}/lib/
ARCHIVE DESTINATION ${BIN_DEST}/lib/
PUBLIC_HEADER DESTINATION ${BIN_DEST}/include/)
# generate pc file for pkg-config
set(PC_FILE cariboulite)
configure_file(cariboulite.pc.in
cariboulite.pc @ONLY)
install(FILES ${CMAKE_BINARY_DIR}/cariboulite.pc
DESTINATION ${BIN_DEST}/lib/pkgconfig/)
#install(TARGETS cariboulite_test_app DESTINATION ${BIN_DEST}/bin/)
install(TARGETS cariboulite_util DESTINATION ${BIN_DEST}/bin/)

Wyświetl plik

@ -1,46 +0,0 @@
# CaribouLite RPI API
This folder contains the low-level and SoapySDR APIs for CaribouLite
# Building
To start from scratch we need to check for the dependencies and install them as needed.
Dependencies installation:
```
# Update the package definitions
sudo apt update
# We used gcc version 8.3+
sudo apt install gcc
# We used libsoapysdr-dev version 0.6.1-4+
sudo apt install libsoapysdr-dev libpthread-stubs0-dev
# cmake version 3.15+
sudo apt install cmake
```
Now to compile we use `cmake` as follows:
```
# create the building directory to contain
# compilation / linking artifacts. if already exists skip
# the creation
mkdir build
# goto the build directory
cd build
# tell cmake to create the Makefiles
# according to the code in the parent directory
cmake ../
# build the code (this will take about 30 seconds @ RPi4)
make
# install the package in your Linux
# environment (including SoapyAPIs)
sudo make install
```
# License
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.

Wyświetl plik

@ -1,11 +0,0 @@
prefix="@BIN_DEST@"
exec_prefix="${prefix}"/bin
libdir="${prefix}/lib"
includedir="${prefix}/include"
Name: @PROJECT_NAME@
Description: @CMAKE_PROJECT_DESCRIPTION@
Version: @PROJECT_VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -l@PROJECT_NAME@

Wyświetl plik

@ -1,261 +0,0 @@
/**
* @file CaribouLite.hpp
* @author David Michaeli
* @date September 2023
* @brief Main Init/Close API
*
* A high level CPP API for CaribouLite
*/
#ifndef __CARIBOULITE_HPP__
#define __CARIBOULITE_HPP__
#include <cariboulite.h>
#include <cariboulite_radio.h>
#include <vector>
#include <complex>
#include <cstddef>
#include <ostream>
#include <iostream>
#include <thread>
#include <memory>
#include <mutex>
#include <functional>
#if __cplusplus <= 199711L
#error This file needs at least a C++11 compliant compiler, try using:
#error $ g++ -std=c++11 ..
#endif
/**
* @brief CaribouLite API Version
*/
class CaribouLiteVersion
{
public:
CaribouLiteVersion(int v, int sv, int rev) {_ver.major_version = v; _ver.minor_version = sv; _ver.revision = rev;}
virtual ~CaribouLiteVersion() {}
friend std::ostream& operator<<(std::ostream& os, const CaribouLiteVersion& c)
{
os << c._ver.major_version << '.' << c._ver.minor_version << '/' << c._ver.revision;
return os;
}
private:
cariboulite_lib_version_st _ver;
};
/**
* @brief CaribouLite Frequency Range
*/
class CaribouLiteFreqRange
{
public:
CaribouLiteFreqRange(float min_hz, float max_hz) : _fMin(min_hz), _fMax(max_hz) {}
virtual ~CaribouLiteFreqRange() {}
friend std::ostream& operator<<(std::ostream& os, const CaribouLiteFreqRange& r)
{
os << "[" << r._fMin << ',' << r._fMax << ']';
return os;
}
private:
float _fMin, _fMax;
};
/**
* @brief CaribouLite Radio Channel
*/
#pragma pack(1)
struct CaribouLiteComplexInt
{
int16_t i;
int16_t q;
};
struct CaribouLiteMeta
{
uint8_t sync;
};
#pragma pack()
class CaribouLite;
class CaribouLiteRadio
{
public:
enum RadioType
{
S1G = 0,
HiF = 1,
};
enum RadioDir
{
Rx = 0,
Tx = 1,
};
enum RxCbType
{
None = 0,
FloatSync = 1,
Float = 2,
IntSync = 3,
Int = 4,
};
public:
CaribouLiteRadio(const cariboulite_radio_state_st* radio, RadioType type, const CaribouLite* parent = NULL);
virtual ~CaribouLiteRadio();
// Gain
void SetAgc(bool agc_on);
bool GetAgc(void);
float GetRxGainMin(void);
float GetRxGainMax(void);
float GetRxGainSteps(void);
void SetRxGain(float gain);
float GetRxGain(void);
// Tx Power
float GetTxPowerMin(void);
float GetTxPowerMax(void);
float GetTxPowerStep(void);
void SetTxPower(float pwr_dBm);
float GetTxPower(void);
// Rx Bandwidth
float GetRxBandwidthMin(void);
float GetRxBandwidthMax(void);
void SetRxBandwidth(float bw_hz);
float GetRxBandwidth(void);
// Tx Bandwidth
float GetTxBandwidthMin(void);
float GetTxBandwidthMax(void);
void SetTxBandwidth(float bw_hz);
float GetTxBandwidth(void);
// Rx Sample Rate
float GetRxSampleRateMin(void);
float GetRxSampleRateMax(void);
void SetRxSampleRate(float sr_hz);
float GetRxSampleRate(void);
// Tx Sample Rate
float GetTxSampleRateMin(void);
float GetTxSampleRateMax(void);
void SetTxSampleRate(float sr_hz);
float GetTxSampleRate(void);
// RSSI and Rx Power and others
float GetRssi(void);
float GetEnergyDet(void);
unsigned char GetTrueRandVal(void);
// Frequency Control
void SetFrequency(float freq_hz);
float GetFrequency(void);
std::vector<CaribouLiteFreqRange> GetFrequencyRange(void);
float GetFrequencyResolution(void);
// Activation
void StartReceiving(std::function<void(CaribouLiteRadio*, const std::complex<float>*, CaribouLiteMeta*, size_t)> on_data_ready, size_t samples_per_chunk = 0);
void StartReceiving(std::function<void(CaribouLiteRadio*, const std::complex<float>*, size_t)> on_data_ready, size_t samples_per_chunk = 0);
void StartReceiving(std::function<void(CaribouLiteRadio*, const CaribouLiteComplexInt*, CaribouLiteMeta*, size_t)> on_data_ready, size_t samples_per_chunk = 0);
void StartReceiving(std::function<void(CaribouLiteRadio*, const CaribouLiteComplexInt*, size_t)> on_data_ready, size_t samples_per_chunk = 0);
void StartReceivingInternal(size_t samples_per_chunk);
void StopReceiving(void);
void StartTransmitting(std::function<void(CaribouLiteRadio*, std::complex<float>*, const bool*, size_t*)> on_data_request, size_t samples_per_chunk);
void StartTransmittingLo(void);
void StartTransmittingCw(void);
void StopTransmitting(void);
bool GetIsTransmittingLo(void);
bool GetIsTransmittingCw(void);
// General
size_t GetNativeMtuSample(void);
std::string GetRadioName(void);
void FlushBuffers(void);
private:
const cariboulite_radio_state_st* _radio;
const CaribouLite* _device;
const RadioType _type;
bool _rx_thread_running;
bool _rx_is_active;
std::thread *_rx_thread;
std::function<void(CaribouLiteRadio*, const std::complex<float>*, CaribouLiteMeta*, size_t)> _on_data_ready_fm;
std::function<void(CaribouLiteRadio*, const std::complex<float>*, size_t)> _on_data_ready_f;
std::function<void(CaribouLiteRadio*, const CaribouLiteComplexInt*, CaribouLiteMeta*, size_t)> _on_data_ready_im;
std::function<void(CaribouLiteRadio*, const CaribouLiteComplexInt*, size_t)> _on_data_ready_i;
size_t _rx_samples_per_chunk;
RxCbType _rxCallbackType;
bool _tx_thread_running;
bool _tx_is_active;
std::thread *_tx_thread;
std::function<void(CaribouLiteRadio*, std::complex<float>*, const bool*, size_t*)> _on_data_request;
size_t _tx_samples_per_chunk;
private:
static void CaribouLiteRxThread(CaribouLiteRadio* radio);
static void CaribouLiteTxThread(CaribouLiteRadio* radio);
};
/**
* @brief CaribouLite Device
*/
class CaribouLite
{
public:
enum LogLevel
{
Verbose,
Info,
None,
};
enum SysVersion
{
Unknown = 0,
CaribouLiteFull = 1,
CaribouLiteISM = 2,
};
protected:
CaribouLite(bool forceFpgaProg = false, LogLevel logLvl = LogLevel::None);
CaribouLite(const CaribouLite& o) = delete;
void operator=(const CaribouLite&) = delete;
void ReleaseResources(void);
public:
~CaribouLite();
bool IsInitialized(void);
CaribouLiteVersion GetApiVersion(void);
unsigned int GetHwSerialNumber(void);
SysVersion GetSystemVersion(void);
std::string GetSystemVersionStr(void);
static std::string GetSystemVersionStr(SysVersion v);
std::string GetHwGuid(void);
CaribouLiteRadio* GetRadioChannel(CaribouLiteRadio::RadioType ch);
// Ststic detection and factory
static CaribouLite &GetInstance(bool forceFpgaProg = false, LogLevel logLvl = LogLevel::None);
static bool DetectBoard(SysVersion *sysVer, std::string& name, std::string& guid);
static void DefaultSignalHandler(void* context, int signal_number, siginfo_t *si);
private:
std::vector<CaribouLiteRadio*> _channels;
SysVersion _systemVersion;
std::string _productName;
std::string _productGuid;
static std::shared_ptr<CaribouLite> _instance;
static std::mutex _instMutex;
};
#endif // __CARIBOULITE_HPP__

Wyświetl plik

@ -1,160 +0,0 @@
#include <exception>
#include "CaribouLite.hpp"
std::shared_ptr<CaribouLite> CaribouLite::_instance = nullptr;
std::mutex CaribouLite::_instMutex;
//==================================================================
void CaribouLite::DefaultSignalHandler(void* context, int signal_number, siginfo_t *si)
{
CaribouLite* cl = (CaribouLite*)context;
std::cout << " >> Signal caught: " << signal_number << std::endl << std::flush;
cl->ReleaseResources();
}
//==================================================================
bool CaribouLite::DetectBoard(SysVersion *sysVer, std::string& name, std::string& guid)
{
cariboulite_version_en hw_ver;
char hw_name[64];
char hw_guid[64];
bool detected = cariboulite_detect_connected_board(&hw_ver, hw_name, hw_guid);
if (detected)
{
name = std::string(hw_name);
guid = std::string(hw_guid);
if (sysVer) *sysVer = (SysVersion)hw_ver;
}
return detected;
}
//==================================================================
CaribouLite &CaribouLite::GetInstance(bool forceFpgaProg, LogLevel logLvl)
{
SysVersion ver;
std::string name, guid;
if (!DetectBoard(&ver, name, guid))
{
throw std::runtime_error("CaribouLite was not detected");
}
std::lock_guard<std::mutex> lock(_instMutex);
if (_instance == nullptr)
{
try
{
_instance = std::shared_ptr<CaribouLite>(new CaribouLite(forceFpgaProg, logLvl));
}
catch (std::exception& e)
{
throw e;
}
}
return *_instance;
}
//==================================================================
CaribouLite::CaribouLite(bool forceFpgaProg, LogLevel logLvl)
{
if (cariboulite_init(forceFpgaProg, (cariboulite_log_level_en)logLvl) != 0)
{
throw std::runtime_error("Driver initialization failed");
}
// register signal handler
cariboulite_register_signal_handler (CaribouLite::DefaultSignalHandler, this);
// get information
DetectBoard(&_systemVersion, _productName, _productGuid);
// populate the radio devices
cariboulite_radio_state_st *radio_s1g = cariboulite_get_radio(cariboulite_channel_s1g);
CaribouLiteRadio* radio_s1g_int = new CaribouLiteRadio(radio_s1g, CaribouLiteRadio::RadioType::S1G, this);
_channels.push_back(radio_s1g_int);
cariboulite_radio_state_st *radio_hif = cariboulite_get_radio(cariboulite_channel_hif);
CaribouLiteRadio* radio_hif_int = new CaribouLiteRadio(radio_hif, CaribouLiteRadio::RadioType::HiF, this);
_channels.push_back(radio_hif_int);
}
//==================================================================
void CaribouLite::ReleaseResources(void)
{
if (!_instance) return;
for (size_t i = 0; i < _instance->_channels.size(); i++)
{
if (_instance->_channels[i]) delete _instance->_channels[i];
_instance->_channels[i] = NULL;
}
if (cariboulite_is_initialized()) cariboulite_close();
}
//==================================================================
CaribouLite::~CaribouLite()
{
if (_instance != nullptr)
{
ReleaseResources();
_instance.reset();
_instance = nullptr;
}
}
//==================================================================
bool CaribouLite::IsInitialized()
{
return cariboulite_is_initialized();
}
//==================================================================
CaribouLiteVersion CaribouLite::GetApiVersion()
{
cariboulite_lib_version_st v = {0};
cariboulite_get_lib_version(&v);
return CaribouLiteVersion(v.major_version, v.minor_version, v.revision);
}
//==================================================================
unsigned int CaribouLite::GetHwSerialNumber()
{
return cariboulite_get_sn();
}
//==================================================================
CaribouLite::SysVersion CaribouLite::GetSystemVersion()
{
return (CaribouLite::SysVersion)cariboulite_get_version();
}
//==================================================================
std::string CaribouLite::GetSystemVersionStr(CaribouLite::SysVersion v)
{
switch(v)
{
case SysVersion::CaribouLiteFull: return std::string("CaribouLite6G"); break;
case SysVersion::CaribouLiteISM: return std::string("CaribouLiteISM"); break;
case SysVersion::Unknown:
default: return std::string("Unknown CaribouLite"); break;
}
return std::string(""); // unreachable.. hopefully
}
//==================================================================
std::string CaribouLite::GetSystemVersionStr(void)
{
return CaribouLite::GetSystemVersionStr(GetSystemVersion());
}
//==================================================================
std::string CaribouLite::GetHwGuid(void)
{
return _productGuid;
}
//==================================================================
CaribouLiteRadio* CaribouLite::GetRadioChannel(CaribouLiteRadio::RadioType ch)
{
return _channels[(int)ch];
}

Wyświetl plik

@ -1,542 +0,0 @@
#include "CaribouLite.hpp"
//=================================================================
void CaribouLiteRadio::CaribouLiteRxThread(CaribouLiteRadio* radio)
{
size_t mtu_size = radio->GetNativeMtuSample();
CaribouLiteComplexInt* rx_buffer = new CaribouLiteComplexInt[mtu_size];
CaribouLiteMeta* rx_meta_buffer = new CaribouLiteMeta[mtu_size];
std::complex<float>* rx_copmlex_data = new std::complex<float>[mtu_size];
while (radio->_rx_thread_running)
{
if (!radio->_rx_is_active)
{
std::this_thread::sleep_for(std::chrono::milliseconds(2));
continue;
}
int ret = cariboulite_radio_read_samples((cariboulite_radio_state_st*)radio->_radio,
(cariboulite_sample_complex_int16*)rx_buffer,
(cariboulite_sample_meta*)rx_meta_buffer,
radio->_rx_samples_per_chunk);
if (ret < 0)
{
if (ret == -1)
{
//printf("reader thread failed to read SMI!\n");
}
ret = 0;
continue;
}
if (ret == 0) continue;
// convert the buffer
if (radio->_rxCallbackType == CaribouLiteRadio::RxCbType::FloatSync || radio->_rxCallbackType == CaribouLiteRadio::RxCbType::Float)
{
for (int i = 0; i < ret; i ++)
{
rx_copmlex_data[i].real(rx_buffer[i].i / 4096.0);
rx_copmlex_data[i].imag(rx_buffer[i].q / 4096.0);
}
}
// notify application
try
{
switch(radio->_rxCallbackType)
{
case (CaribouLiteRadio::RxCbType::FloatSync): if (radio->_on_data_ready_fm) radio->_on_data_ready_fm(radio, rx_copmlex_data, rx_meta_buffer, ret); break;
case (CaribouLiteRadio::RxCbType::Float): if (radio->_on_data_ready_f) radio->_on_data_ready_f(radio, rx_copmlex_data, ret); break;
case (CaribouLiteRadio::RxCbType::IntSync): if (radio->_on_data_ready_im) radio->_on_data_ready_im(radio, rx_buffer, rx_meta_buffer, ret); break;
case (CaribouLiteRadio::RxCbType::Int): if (radio->_on_data_ready_i) radio->_on_data_ready_i(radio, rx_buffer, ret); break;
case (CaribouLiteRadio::RxCbType::None):
default: break;
}
}
catch (std::exception &e)
{
std::cout << "OnDataReady Exception: " << e.what() << std::endl;
}
}
delete[]rx_buffer;
delete[]rx_meta_buffer;
delete[]rx_copmlex_data;
}
//==================================================================
void CaribouLiteRadio::CaribouLiteTxThread(CaribouLiteRadio* radio)
{
while (radio->_tx_thread_running)
{
if (!radio->_tx_is_active)
{
std::this_thread::sleep_for(std::chrono::milliseconds(4));
continue;
}
// TBD
}
}
//==================================================================
CaribouLiteRadio::CaribouLiteRadio(const cariboulite_radio_state_st* radio, RadioType type, const CaribouLite* parent)
: _radio(radio), _device(parent), _type(type), _rxCallbackType(RxCbType::None)
{
_rx_thread_running = true;
_rx_thread = new std::thread(CaribouLiteRadio::CaribouLiteRxThread, this);
_tx_thread_running = true;
_tx_thread = new std::thread(CaribouLiteRadio::CaribouLiteTxThread, this);
}
//==================================================================
CaribouLiteRadio::~CaribouLiteRadio()
{
//std::cout << "Destructor of Radio" << std::endl;
StopReceiving();
StopTransmitting();
_rx_thread_running = false;
_rx_thread->join();
if (_rx_thread) delete _rx_thread;
_tx_thread_running = false;
_tx_thread->join();
if (_tx_thread) delete _tx_thread;
}
// Gain
//==================================================================
void CaribouLiteRadio::SetAgc(bool agc_on)
{
int gain = 0;
bool temp = false;
cariboulite_radio_get_rx_gain_control((cariboulite_radio_state_st*)_radio, &temp, &gain);
cariboulite_radio_set_rx_gain_control((cariboulite_radio_state_st*)_radio, agc_on, gain);
}
//==================================================================
bool CaribouLiteRadio::GetAgc()
{
int gain = 0;
bool temp = false;
cariboulite_radio_get_rx_gain_control((cariboulite_radio_state_st*)_radio, &temp, &gain);
return temp;
}
//==================================================================
float CaribouLiteRadio::GetRxGainMin()
{
int rx_min_gain_value_db, rx_max_gain_value_db, rx_gain_value_resolution_db;
cariboulite_radio_get_rx_gain_limits((cariboulite_radio_state_st*)_radio,
&rx_min_gain_value_db,
&rx_max_gain_value_db,
&rx_gain_value_resolution_db);
return rx_min_gain_value_db;
}
//==================================================================
float CaribouLiteRadio::GetRxGainMax()
{
int rx_min_gain_value_db, rx_max_gain_value_db, rx_gain_value_resolution_db;
cariboulite_radio_get_rx_gain_limits((cariboulite_radio_state_st*)_radio,
&rx_min_gain_value_db,
&rx_max_gain_value_db,
&rx_gain_value_resolution_db);
return rx_max_gain_value_db;
}
//==================================================================
float CaribouLiteRadio::GetRxGainSteps()
{
int rx_min_gain_value_db, rx_max_gain_value_db, rx_gain_value_resolution_db;
cariboulite_radio_get_rx_gain_limits((cariboulite_radio_state_st*)_radio,
&rx_min_gain_value_db,
&rx_max_gain_value_db,
&rx_gain_value_resolution_db);
return rx_gain_value_resolution_db;
}
//==================================================================
void CaribouLiteRadio::SetRxGain(float gain)
{
bool temp = false;
cariboulite_radio_get_rx_gain_control((cariboulite_radio_state_st*)_radio, &temp, NULL);
cariboulite_radio_set_rx_gain_control((cariboulite_radio_state_st*)_radio, temp, (int)gain);
}
//==================================================================
float CaribouLiteRadio::GetRxGain()
{
int igain = 0;
cariboulite_radio_get_rx_gain_control((cariboulite_radio_state_st*)_radio, NULL, &igain);
return (float)igain;
}
// Tx Power
//==================================================================
float CaribouLiteRadio::GetTxPowerMin()
{
return -15.0f;
}
//==================================================================
float CaribouLiteRadio::GetTxPowerMax()
{
return 18.0f;
}
//==================================================================
float CaribouLiteRadio::GetTxPowerStep()
{
return 1.0f;
}
//==================================================================
void CaribouLiteRadio::SetTxPower(float pwr_dBm)
{
cariboulite_radio_set_tx_power((cariboulite_radio_state_st*)_radio, (int)pwr_dBm);
}
//==================================================================
float CaribouLiteRadio::GetTxPower()
{
int itx_pwr = 0;
cariboulite_radio_get_tx_power((cariboulite_radio_state_st*)_radio, &itx_pwr);
return (float)itx_pwr;
}
// Rx Bandwidth
//==================================================================
float CaribouLiteRadio::GetRxBandwidthMin()
{
return 200000.0f;
}
//==================================================================
float CaribouLiteRadio::GetRxBandwidthMax()
{
return 2500000.0f;
}
//==================================================================
void CaribouLiteRadio::SetRxBandwidth(float bw_hz)
{
cariboulite_radio_set_rx_bandwidth_flt((cariboulite_radio_state_st*)_radio, bw_hz);
}
//==================================================================
float CaribouLiteRadio::GetRxBandwidth()
{
float bw = 0;
cariboulite_radio_get_rx_bandwidth_flt((cariboulite_radio_state_st*)_radio, &bw);
return bw;
}
// Tx Bandwidth
//==================================================================
float CaribouLiteRadio::GetTxBandwidthMin()
{
return 80000.0f;
}
//==================================================================
float CaribouLiteRadio::GetTxBandwidthMax()
{
return 1000000.0f;
}
//==================================================================
void CaribouLiteRadio::SetTxBandwidth(float bw_hz)
{
cariboulite_radio_set_tx_bandwidth_flt((cariboulite_radio_state_st*)_radio, bw_hz);
}
//==================================================================
float CaribouLiteRadio::GetTxBandwidth()
{
float bw = 0;
cariboulite_radio_get_tx_bandwidth_flt((cariboulite_radio_state_st*)_radio, &bw);
return bw;
}
// Rx Sample Rate
//==================================================================
float CaribouLiteRadio::GetRxSampleRateMin()
{
return 400000.0f;
}
//==================================================================
float CaribouLiteRadio::GetRxSampleRateMax()
{
return 4000000.0f;
}
//==================================================================
void CaribouLiteRadio::SetRxSampleRate(float sr_hz)
{
cariboulite_radio_set_rx_sample_rate_flt((cariboulite_radio_state_st*)_radio, sr_hz);
}
//==================================================================
float CaribouLiteRadio::GetRxSampleRate()
{
float sr = 0.0f;
cariboulite_radio_get_rx_sample_rate_flt((cariboulite_radio_state_st*)_radio, &sr);
return sr;
}
// Tx Sample Rate
//==================================================================
float CaribouLiteRadio::GetTxSampleRateMin()
{
return 400000.0f;
}
//==================================================================
float CaribouLiteRadio::GetTxSampleRateMax()
{
return 4000000.0f;
}
//==================================================================
void CaribouLiteRadio::SetTxSampleRate(float sr_hz)
{
cariboulite_radio_set_tx_samp_cutoff_flt((cariboulite_radio_state_st*)_radio, sr_hz);
}
//==================================================================
float CaribouLiteRadio::GetTxSampleRate()
{
float sr = 0.0f;
cariboulite_radio_get_tx_samp_cutoff_flt((cariboulite_radio_state_st*)_radio, &sr);
return sr;
}
// RSSI and Rx Power and others
//==================================================================
float CaribouLiteRadio::GetRssi()
{
float rssi = 0.0f;
cariboulite_radio_get_rssi((cariboulite_radio_state_st*)_radio, &rssi);
return rssi;
}
//==================================================================
float CaribouLiteRadio::GetEnergyDet()
{
float ed = 0.0f;
cariboulite_radio_get_energy_det((cariboulite_radio_state_st*)_radio, &ed);
return ed;
}
//==================================================================
unsigned char CaribouLiteRadio::GetTrueRandVal()
{
unsigned char val = 0;
cariboulite_radio_get_rand_val((cariboulite_radio_state_st*)_radio, &val);
return val;
}
// Frequency Control
//==================================================================
void CaribouLiteRadio::SetFrequency(float freq_hz)
{
if (!cariboulite_frequency_available((cariboulite_channel_en)_type, freq_hz))
{
char msg[128] = {0};
sprintf(msg, "Frequency out or range %.2f Hz on %s", freq_hz, GetRadioName().c_str());
throw std::invalid_argument(msg);
}
double freq_dbl = freq_hz;
if (cariboulite_radio_set_frequency((cariboulite_radio_state_st*)_radio,
true,
&freq_dbl) != 0)
{
char msg[128] = {0};
sprintf(msg, "Frequency setting on %s failed", GetRadioName().c_str());
throw std::runtime_error(msg);
}
}
//==================================================================
float CaribouLiteRadio::GetFrequency()
{
double freq = 0;
cariboulite_radio_get_frequency((cariboulite_radio_state_st*)_radio,
&freq, NULL, NULL);
return freq;
}
//==================================================================
std::vector<CaribouLiteFreqRange> CaribouLiteRadio::GetFrequencyRange()
{
std::vector<CaribouLiteFreqRange> ranges;
float freq_mins[10];
float freq_maxs[10];
int num = 0;
cariboulite_get_frequency_limits((cariboulite_channel_en)_type, freq_mins, freq_maxs, &num);
for (int i = 0; i < num; i++)
{
ranges.push_back(CaribouLiteFreqRange(freq_mins[i], freq_maxs[i]));
}
return ranges;
}
//==================================================================
float CaribouLiteRadio::GetFrequencyResolution()
{
// TBD: todo calculate it according to the real hardware specs
return 1.0f;
}
// Activation
//==================================================================
void CaribouLiteRadio::StartReceivingInternal(size_t samples_per_chunk)
{
_rx_samples_per_chunk = (samples_per_chunk==0)?GetNativeMtuSample():samples_per_chunk;
if (_rx_samples_per_chunk > GetNativeMtuSample())
{
_rx_samples_per_chunk = GetNativeMtuSample();
}
// make sure only one radio is receiving at once
CaribouLiteRadio* otherRadio = ((CaribouLite*)_device)->GetRadioChannel((_type==RadioType::S1G)?(RadioType::HiF):(RadioType::S1G));
otherRadio->StopReceiving();
cariboulite_radio_activate_channel((cariboulite_radio_state_st*)_radio, cariboulite_channel_dir_rx, true);
_rx_is_active = true;
}
//==================================================================
void CaribouLiteRadio::StartReceiving(std::function<void(CaribouLiteRadio*, const std::complex<float>*, CaribouLiteMeta*, size_t)> on_data_ready, size_t samples_per_chunk)
{
_on_data_ready_fm = on_data_ready;
_rxCallbackType = RxCbType::FloatSync;
StartReceivingInternal(samples_per_chunk);
}
//==================================================================
void CaribouLiteRadio::StartReceiving(std::function<void(CaribouLiteRadio*, const std::complex<float>*, size_t)> on_data_ready, size_t samples_per_chunk)
{
_on_data_ready_f = on_data_ready;
_rxCallbackType = RxCbType::Float;
StartReceivingInternal(samples_per_chunk);
}
//==================================================================
void CaribouLiteRadio::StartReceiving(std::function<void(CaribouLiteRadio*, const CaribouLiteComplexInt*, CaribouLiteMeta*, size_t)> on_data_ready, size_t samples_per_chunk)
{
_on_data_ready_im = on_data_ready;
_rxCallbackType = RxCbType::IntSync;
StartReceivingInternal(samples_per_chunk);
}
//==================================================================
void CaribouLiteRadio::StartReceiving(std::function<void(CaribouLiteRadio*, const CaribouLiteComplexInt*, size_t)> on_data_ready, size_t samples_per_chunk)
{
_on_data_ready_i = on_data_ready;
_rxCallbackType = RxCbType::Int;
StartReceivingInternal(samples_per_chunk);
}
//==================================================================
void CaribouLiteRadio::StopReceiving()
{
_rx_is_active = false;
cariboulite_radio_activate_channel((cariboulite_radio_state_st*)_radio, cariboulite_channel_dir_rx, false);
}
//==================================================================
void CaribouLiteRadio::StartTransmitting(std::function<void(CaribouLiteRadio*, std::complex<float>*, const bool*, size_t*)> on_data_request, size_t samples_per_chunk)
{
_rx_is_active = false;
_on_data_request = on_data_request;
_tx_samples_per_chunk = samples_per_chunk;
cariboulite_radio_activate_channel((cariboulite_radio_state_st*)_radio, cariboulite_channel_dir_rx, false);
cariboulite_radio_set_cw_outputs((cariboulite_radio_state_st*)_radio, false, false);
cariboulite_radio_activate_channel((cariboulite_radio_state_st*)_radio, cariboulite_channel_dir_tx, true);
_tx_is_active = true;
}
//==================================================================
void CaribouLiteRadio::StartTransmittingLo()
{
_rx_is_active = false;
_tx_is_active = false;
cariboulite_radio_activate_channel((cariboulite_radio_state_st*)_radio, cariboulite_channel_dir_tx, false);
cariboulite_radio_set_cw_outputs((cariboulite_radio_state_st*)_radio, true, false);
cariboulite_radio_activate_channel((cariboulite_radio_state_st*)_radio, cariboulite_channel_dir_tx, true);
}
//==================================================================
void CaribouLiteRadio::StartTransmittingCw()
{
_rx_is_active = false;
_tx_is_active = false;
cariboulite_radio_activate_channel((cariboulite_radio_state_st*)_radio, cariboulite_channel_dir_tx, false);
cariboulite_radio_set_cw_outputs((cariboulite_radio_state_st*)_radio, false, true);
cariboulite_radio_activate_channel((cariboulite_radio_state_st*)_radio, cariboulite_channel_dir_tx, true);
}
//==================================================================
void CaribouLiteRadio::StopTransmitting()
{
_tx_is_active = false;
cariboulite_radio_set_cw_outputs((cariboulite_radio_state_st*)_radio, false, false);
cariboulite_radio_activate_channel((cariboulite_radio_state_st*)_radio, cariboulite_channel_dir_tx, false);
}
//==================================================================
bool CaribouLiteRadio::GetIsTransmittingLo()
{
bool lo_out = false;
cariboulite_radio_get_cw_outputs((cariboulite_radio_state_st*)_radio, &lo_out, NULL);
return lo_out;
}
//==================================================================
bool CaribouLiteRadio::GetIsTransmittingCw()
{
bool cw_out = false;
cariboulite_radio_get_cw_outputs((cariboulite_radio_state_st*)_radio, NULL, &cw_out);
return cw_out;
}
// General
//==================================================================
size_t CaribouLiteRadio::GetNativeMtuSample()
{
return cariboulite_radio_get_native_mtu_size_samples((cariboulite_radio_state_st*)_radio);
}
//==================================================================
std::string CaribouLiteRadio::GetRadioName()
{
char name[64];
cariboulite_get_channel_name((cariboulite_channel_en)_type, name, sizeof(name));
return std::string(name);
}
//==================================================================
void CaribouLiteRadio::FlushBuffers()
{
int res = cariboulite_flush_pipeline();
}

Wyświetl plik

@ -1,775 +0,0 @@
#include <stdio.h>
#include "cariboulite.h"
#include "cariboulite_setup.h"
//=================================================
typedef enum
{
app_selection_hard_reset_fpga = 0,
app_selection_soft_reset_fpga,
app_selection_versions,
app_selection_program_fpga,
app_selection_self_test,
app_selection_fpga_dig_control,
app_selection_fpga_rffe_control,
app_selection_fpga_smi_fifo,
app_selection_modem_tx_cw,
app_selection_modem_rx_iq,
app_selection_synthesizer,
app_selection_quit = 99,
} app_selection_en;
typedef void (*handle_cb)(sys_st *sys);
typedef struct
{
app_selection_en num;
handle_cb handle;
char text[256];
} app_menu_item_st;
static void app_hard_reset_fpga(sys_st *sys);
static void app_soft_reset_fpga(sys_st *sys);
static void app_versions_printout(sys_st *sys);
static void app_fpga_programming(sys_st *sys);
static void app_self_test(sys_st *sys);
static void fpga_control_io(sys_st *sys);
static void fpga_rf_control(sys_st *sys);
static void fpga_smi_fifo(sys_st *sys);
static void modem_tx_cw(sys_st *sys);
static void modem_rx_iq(sys_st *sys);
static void synthesizer(sys_st *sys);
//=================================================
app_menu_item_st handles[] =
{
{app_selection_hard_reset_fpga, app_hard_reset_fpga, "Hard reset FPGA",},
{app_selection_soft_reset_fpga, app_soft_reset_fpga, "Soft reset FPGA",},
{app_selection_versions, app_versions_printout, "Print board info and versions",},
{app_selection_program_fpga, app_fpga_programming, "Program FPGA",},
{app_selection_self_test, app_self_test, "Perform a Self-Test",},
{app_selection_fpga_dig_control, fpga_control_io, "FPGA Digital I/O",},
{app_selection_fpga_rffe_control, fpga_rf_control, "FPGA RFFE control",},
{app_selection_fpga_smi_fifo, fpga_smi_fifo, "FPGA SMI fifo status",},
{app_selection_modem_tx_cw, modem_tx_cw, "Modem transmit CW signal",},
{app_selection_modem_rx_iq, modem_rx_iq, "Modem receive I/Q stream",},
{app_selection_synthesizer, synthesizer, "Synthesizer 85-4200 MHz",},
};
#define NUM_HANDLES (int)(sizeof(handles)/sizeof(app_menu_item_st))
//=================================================
static void app_hard_reset_fpga(sys_st *sys)
{
caribou_fpga_hard_reset(&sys->fpga);
}
//=================================================
static void app_soft_reset_fpga(sys_st *sys)
{
caribou_fpga_soft_reset(&sys->fpga);
}
//=================================================
static void app_versions_printout(sys_st *sys)
{
printf("Board Information (HAT)\n");
cariboulite_print_board_info(sys, false);
caribou_fpga_get_versions (&sys->fpga, NULL);
at86rf215_print_version(&sys->modem);
printf("\nLibrary Versions:\n");
cariboulite_lib_version_st lib_vers = {0};
cariboulite_lib_version(&lib_vers);
printf(" (Major, Minor, Rev): (%d, %d, %d)\n", lib_vers.major_version,
lib_vers.minor_version,
lib_vers.revision);
}
//=================================================
static void app_fpga_programming(sys_st *sys)
{
app_hard_reset_fpga(sys);
printf("FPGA Programming:\n");
sys->force_fpga_reprogramming = true;
int res = cariboulite_configure_fpga (sys, cariboulite_firmware_source_blob, NULL);
if (res < 0)
{
printf(" ERROR: FPGA programming failed `%d`\n", res);
return;
}
printf(" FPGA programming successful, Versions:\n");
caribou_fpga_soft_reset(&sys->fpga);
io_utils_usleep(100000);
caribou_fpga_get_versions (&sys->fpga, NULL);
caribou_fpga_set_io_ctrl_mode (&sys->fpga, 0, caribou_fpga_io_ctrl_rfm_low_power);
}
//=================================================
static void app_self_test(sys_st *sys)
{
cariboulite_self_test_result_st res = {0};
cariboulite_self_test(sys, &res);
}
//=================================================
static void fpga_control_io(sys_st *sys)
{
int choice = 0;
int led0 = 0, led1 = 0, btn = 0, cfg = 0;
while (1)
{
caribou_fpga_get_io_ctrl_dig (&sys->fpga, &led0, &led1, &btn, &cfg);
printf("\n FPGA Digital I/O state:\n");
printf(" LED0 = %d, LED1 = %d, BTN = %d, CFG = (%d, %d, %d, %d)\n",
led0, led1, btn,
(cfg >> 3) & (0x1 == 1),
(cfg >> 2) & (0x1 == 1),
(cfg >> 1) & (0x1 == 1),
(cfg >> 0) & (0x1 == 1));
printf(" [1] Toggle LED0\n [2] Toggle LED1\n [99] Return to Menu\n Choice:");
if (scanf("%d", &choice) != 1) continue;
switch(choice)
{
case 1:
led0 = !led0;
caribou_fpga_set_io_ctrl_dig (&sys->fpga, led0, led1);
break;
case 2:
led1 = !led1;
caribou_fpga_set_io_ctrl_dig (&sys->fpga, led0, led1);
break;
case 99: return;
default: continue;
}
}
}
//=================================================
static void fpga_rf_control(sys_st *sys)
{
int choice = 0;
uint8_t debug = 0;
caribou_fpga_io_ctrl_rfm_en mode;
while (1)
{
caribou_fpga_get_io_ctrl_mode (&sys->fpga, &debug, &mode);
printf("\n FPGA RFFE state:\n");
printf(" DEBUG = %d, MODE: '%s'\n", debug, caribou_fpga_get_mode_name (mode));
printf(" Available Modes:\n");
for (int i=caribou_fpga_io_ctrl_rfm_low_power; i<=caribou_fpga_io_ctrl_rfm_tx_hipass; i++)
{
printf(" [%d] %s\n", i, caribou_fpga_get_mode_name (i));
}
printf(" [99] Return to main menu\n");
printf("\n Choose a new mode: ");
if (scanf("%d", &choice) != 1) continue;
if (choice == 99) return;
if (choice <caribou_fpga_io_ctrl_rfm_low_power || choice >caribou_fpga_io_ctrl_rfm_tx_hipass)
{
printf(" Wrong choice '%d'\n", choice);
continue;
}
caribou_fpga_set_io_ctrl_mode (&sys->fpga, 0, (caribou_fpga_io_ctrl_rfm_en)choice);
}
}
//=================================================
static void fpga_smi_fifo(sys_st *sys)
{
caribou_fpga_smi_fifo_status_st status = {0};
uint8_t *val = (uint8_t *)&status;
caribou_fpga_get_smi_ctrl_fifo_status (&sys->fpga, &status);
printf(" FPGA SMI info (%02X):\n", *val);
printf(" RX FIFO EMPTY: %d\n", status.rx_fifo_empty);
printf(" TX FIFO FULL: %d\n", status.tx_fifo_full);
printf(" RX CHANNEL: %d\n", status.smi_channel);
printf(" RX SMI TEST: %d\n", status.i_smi_test);
}
//=================================================
static void modem_tx_cw(sys_st *sys)
{
double current_freq_lo = 900e6;
double current_freq_hi = 2400e6;
float current_power_lo = -12;
float current_power_hi = -12;
int state_lo = 0;
int state_hi = 0;
int choice = 0;
cariboulite_radio_state_st *radio_low = &sys->radio_low;
cariboulite_radio_state_st *radio_hi = &sys->radio_high;
// output power
cariboulite_radio_set_tx_power(radio_low, current_power_lo);
cariboulite_radio_set_tx_power(radio_hi, current_power_hi);
// frequency
cariboulite_radio_set_frequency(radio_low, true, &current_freq_lo);
cariboulite_radio_set_frequency(radio_hi, true, &current_freq_hi);
// deactivate - just to be sure
cariboulite_radio_activate_channel(radio_low, cariboulite_channel_dir_tx, false);
cariboulite_radio_activate_channel(radio_hi, cariboulite_channel_dir_tx, false);
// setup cw outputs from modem
cariboulite_radio_set_cw_outputs(radio_low, false, true);
cariboulite_radio_set_cw_outputs(radio_hi, false, true);
// synchronize
cariboulite_radio_sync_information(radio_low);
cariboulite_radio_sync_information(radio_hi);
// update params
current_freq_lo = radio_low->actual_rf_frequency;
current_freq_hi = radio_hi->actual_rf_frequency;
current_power_lo = radio_low->tx_power;
current_power_hi = radio_hi->tx_power;
state_lo = radio_low->state == cariboulite_radio_state_cmd_rx;
state_hi = radio_hi->state == cariboulite_radio_state_cmd_rx;
while (1)
{
printf(" Parameters:\n");
printf(" [1] Frequency @ Low Channel [%.2f MHz]\n", current_freq_lo);
printf(" [2] Frequency @ High Channel [%.2f MHz]\n", current_freq_hi);
printf(" [3] Power out @ Low Channel [%.2f dBm]\n", current_power_lo);
printf(" [4] Power out @ High Channel [%.2f dBm]\n", current_power_hi);
printf(" [5] On/off CW output @ Low Channel [Currently %s]\n", state_lo?"ON":"OFF");
printf(" [6] On/off CW output @ High Channel [Currently %s]\n", state_hi?"ON":"OFF");
printf(" [7] Low Channel decrease frequency (5MHz)\n");
printf(" [8] Low Channel increase frequency (5MHz)\n");
printf(" [9] Hi Channel decrease frequency (5MHz)\n");
printf(" [10] Hi Channel increase frequency (5MHz)\n");
printf(" [99] Return to Main Menu\n");
printf(" Choice: ");
if (scanf("%d", &choice) != 1) continue;
switch (choice)
{
//---------------------------------------------------------
case 1:
{
printf(" Enter frequency @ Low Channel [Hz]: ");
if (scanf("%lf", &current_freq_lo) != 1) continue;
cariboulite_radio_activate_channel(radio_low, cariboulite_channel_dir_tx, false);
cariboulite_radio_set_frequency(radio_low, true, &current_freq_lo);
cariboulite_radio_set_tx_power(radio_low, current_power_lo);
if (state_lo)
{
cariboulite_radio_activate_channel(radio_low, cariboulite_channel_dir_tx, true);
}
current_freq_lo = radio_low->actual_rf_frequency;
}
break;
//---------------------------------------------------------
case 2:
{
printf(" Enter frequency @ High Channel [Hz]: ");
if (scanf("%lf", &current_freq_hi) != 1) continue;
cariboulite_radio_activate_channel(radio_hi, cariboulite_channel_dir_tx, false);
cariboulite_radio_set_frequency(radio_hi, true, &current_freq_hi);
cariboulite_radio_set_tx_power(radio_hi, current_power_hi);
if (state_hi)
{
cariboulite_radio_activate_channel(radio_hi, cariboulite_channel_dir_tx, true);
}
current_freq_hi = radio_hi->actual_rf_frequency;
}
break;
//---------------------------------------------------------
case 3:
{
printf(" Enter power @ Low Channel [dBm]: ");
if (scanf("%f", &current_power_lo) != 1) continue;
cariboulite_radio_set_tx_power(radio_low, current_power_lo);
current_power_lo = radio_low->tx_power;
}
break;
//---------------------------------------------------------
case 4:
{
printf(" Enter power @ High Channel [dBm]: ");
if (scanf("%f", &current_power_hi) != 1) continue;
cariboulite_radio_set_tx_power(radio_hi, current_power_hi);
current_power_hi = radio_hi->tx_power;
}
break;
//---------------------------------------------------------
case 5:
{
state_lo = !state_lo;
if (state_lo == 1) cariboulite_radio_set_tx_power(radio_low, current_power_lo);
cariboulite_radio_set_cw_outputs(radio_low, false, state_lo);
cariboulite_radio_activate_channel(radio_low, cariboulite_channel_dir_tx, state_lo);
}
break;
//---------------------------------------------------------
case 6:
{
state_hi = !state_hi;
if (state_hi == 1) cariboulite_radio_set_tx_power(radio_hi, current_power_hi);
cariboulite_radio_set_cw_outputs(radio_hi, false, state_hi);
cariboulite_radio_activate_channel(radio_hi, cariboulite_channel_dir_tx, state_hi);
}
break;
//---------------------------------------------------------
case 7:
{
current_freq_lo -= 5e6;
cariboulite_radio_activate_channel(radio_low, cariboulite_channel_dir_tx, false);
cariboulite_radio_set_frequency(radio_low, true, &current_freq_lo);
cariboulite_radio_set_tx_power(radio_low, current_power_lo);
if (state_lo)
{
cariboulite_radio_activate_channel(radio_low, cariboulite_channel_dir_tx, true);
}
//current_freq_lo = radio_low->actual_rf_frequency;
}
break;
//---------------------------------------------------------
case 8:
{
current_freq_lo += 5e6;
cariboulite_radio_activate_channel(radio_low, cariboulite_channel_dir_tx, false);
cariboulite_radio_set_frequency(radio_low, true, &current_freq_lo);
cariboulite_radio_set_tx_power(radio_low, current_power_lo);
if (state_lo)
{
cariboulite_radio_activate_channel(radio_low, cariboulite_channel_dir_tx, true);
}
//current_freq_lo = radio_low->actual_rf_frequency;
}
break;
//---------------------------------------------------------
case 9:
{
current_freq_hi -= 5e6;
cariboulite_radio_activate_channel(radio_hi, cariboulite_channel_dir_tx, false);
cariboulite_radio_set_frequency(radio_hi, true, &current_freq_hi);
cariboulite_radio_set_tx_power(radio_hi, current_power_hi);
if (state_hi)
{
cariboulite_radio_activate_channel(radio_hi, cariboulite_channel_dir_tx, true);
}
//current_freq_hi = radio_hi->actual_rf_frequency;
}
break;
//---------------------------------------------------------
case 10:
{
current_freq_hi += 5e6;
cariboulite_radio_activate_channel(radio_hi, cariboulite_channel_dir_tx, false);
cariboulite_radio_set_frequency(radio_hi, true, &current_freq_hi);
cariboulite_radio_set_tx_power(radio_hi, current_power_hi);
if (state_hi)
{
cariboulite_radio_activate_channel(radio_hi, cariboulite_channel_dir_tx, true);
}
//current_freq_hi = radio_hi->actual_rf_frequency;
}
break;
//---------------------------------------------------------
case 99:
{
return;
}
break;
//---------------------------------------------------------
default: break;
}
}
}
//=================================================
typedef struct
{
bool active;
sys_st *sys;
cariboulite_radio_state_st *radio_low;
cariboulite_radio_state_st *radio_hi;
bool *low_active;
bool *high_active;
} iq_test_reader_st;
static void print_iq(char* prefix, cariboulite_sample_complex_int16* buffer, size_t num_samples, int num_head_tail)
{
int i;
if (num_samples == 0) return;
printf("NS: %lu > ", num_samples);
for (i = 0; i < num_head_tail; i++)
{
printf("[%d, %d] ", buffer[i].i, buffer[i].q);
}
printf(". . . ");
for (i = num_samples-num_head_tail; i < (int)num_samples; i++)
{
printf("[%d, %d] ", buffer[i].i, buffer[i].q);
}
printf("\n");
}
static void* reader_thread_func(void* arg)
{
iq_test_reader_st* ctrl = (iq_test_reader_st*)arg;
cariboulite_radio_state_st *cur_radio = NULL;
size_t read_len = caribou_smi_get_native_batch_samples(&ctrl->sys->smi);
// allocate buffer
cariboulite_sample_complex_int16* buffer = malloc(sizeof(cariboulite_sample_complex_int16)*read_len);
cariboulite_sample_meta* metadata = malloc(sizeof(cariboulite_sample_meta)*read_len);
printf("Entering sampling thread\n");
while (ctrl->active)
{
if (*ctrl->low_active)
{
cur_radio = ctrl->radio_low;
}
else if (*ctrl->high_active)
{
cur_radio = ctrl->radio_hi;
}
else
{
cur_radio = NULL;
usleep(10000);
}
if (cur_radio)
{
int ret = cariboulite_radio_read_samples(cur_radio, buffer, metadata, read_len);
if (ret < 0)
{
if (ret == -1)
{
printf("reader thread failed to read SMI!\n");
}
}
else print_iq("Rx", buffer, ret, 4);
}
}
printf("Leaving sampling thread\n");
free(buffer);
free(metadata);
return NULL;
}
static void modem_rx_iq(sys_st *sys)
{
int choice = 0;
bool low_active_rx = false;
bool high_active_rx = false;
bool push_debug = false;
bool pull_debug = false;
bool lfsr_debug = false;
double current_freq_lo = 900e6;
double current_freq_hi = 2400e6;
iq_test_reader_st ctrl = {0};
// create the radio
cariboulite_radio_state_st *radio_low = &sys->radio_low;
cariboulite_radio_state_st *radio_hi = &sys->radio_high;
ctrl.active = true;
ctrl.radio_low = radio_low;
ctrl.radio_hi = radio_hi;
ctrl.sys = sys;
ctrl.low_active = &low_active_rx;
ctrl.high_active = &high_active_rx;
// start the reader thread
pthread_t reader_thread;
if (pthread_create(&reader_thread, NULL, &reader_thread_func, &ctrl) != 0)
{
printf("reader thread creation failed\n");
return;
}
// frequency
cariboulite_radio_set_frequency(radio_low, true, &current_freq_lo);
cariboulite_radio_set_frequency(radio_hi, true, &current_freq_hi);
// synchronize
cariboulite_radio_sync_information(radio_low);
cariboulite_radio_sync_information(radio_hi);
cariboulite_radio_activate_channel(radio_low, cariboulite_channel_dir_rx, false);
cariboulite_radio_activate_channel(radio_hi, cariboulite_channel_dir_rx, false);
caribou_smi_set_debug_mode(&sys->smi, caribou_smi_none);
while (1)
{
printf(" Parameters:\n");
printf(" [1] Ch1 (%.5f MHz) RX %s\n", current_freq_lo / 1e6, low_active_rx?"Active":"Not Active");
printf(" [2] Ch2 (%.5f MHz) RX %s\n", current_freq_hi / 1e6, high_active_rx?"Active":"Not Active");
printf(" [3] Push Debug %s\n", push_debug?"Active":"Not Active");
printf(" [4] Pull Debug %s\n", pull_debug?"Active":"Not Active");
printf(" [5] LFSR Debug %s\n", lfsr_debug?"Active":"Not Active");
printf(" [99] Return to main menu\n");
printf(" Choice: ");
if (scanf("%d", &choice) != 1) continue;
switch (choice)
{
//--------------------------------------------
case 1:
{
if (!low_active_rx && high_active_rx)
{
// if high is currently active - deactivate it
high_active_rx = false;
printf("Turning on Low channel => High channel off\n");
cariboulite_radio_activate_channel(radio_hi, cariboulite_channel_dir_rx, false);
}
low_active_rx = !low_active_rx;
cariboulite_radio_activate_channel(radio_low, cariboulite_channel_dir_rx, low_active_rx);
}
break;
//--------------------------------------------
case 2:
{
if (!high_active_rx && low_active_rx)
{
// if low is currently active - deactivate it
low_active_rx = false;
printf("Turning on High channel => Low channel off\n");
cariboulite_radio_activate_channel(radio_low, cariboulite_channel_dir_rx, false);
}
high_active_rx = !high_active_rx;
cariboulite_radio_activate_channel(radio_hi, cariboulite_channel_dir_rx, high_active_rx);
}
break;
//--------------------------------------------
case 3:
{
push_debug = !push_debug;
if (push_debug)
{
pull_debug = false;
lfsr_debug = false;
caribou_smi_set_debug_mode(&sys->smi, caribou_smi_push);
}
else caribou_smi_set_debug_mode(&sys->smi, caribou_smi_none);
caribou_fpga_set_debug_modes (&sys->fpga, push_debug, pull_debug, lfsr_debug);
}
break;
//--------------------------------------------
case 4:
{
pull_debug = !pull_debug;
if (pull_debug)
{
push_debug = false;
lfsr_debug = false;
caribou_smi_set_debug_mode(&sys->smi, caribou_smi_pull);
}
else caribou_smi_set_debug_mode(&sys->smi, caribou_smi_none);
caribou_fpga_set_debug_modes (&sys->fpga, push_debug, pull_debug, lfsr_debug);
}
break;
//--------------------------------------------
case 5:
{
lfsr_debug = !lfsr_debug;
if (lfsr_debug)
{
push_debug = false;
pull_debug = false;
caribou_smi_set_debug_mode(&sys->smi, caribou_smi_lfsr);
}
else caribou_smi_set_debug_mode(&sys->smi, caribou_smi_none);
caribou_fpga_set_debug_modes (&sys->fpga, push_debug, pull_debug, lfsr_debug);
}
break;
//--------------------------------------------
case 99:
low_active_rx = false;
high_active_rx = false;
ctrl.active = false;
pthread_join(reader_thread, NULL);
cariboulite_radio_activate_channel(radio_low, cariboulite_channel_dir_rx, false);
cariboulite_radio_activate_channel(radio_hi, cariboulite_channel_dir_rx, false);
return;
//--------------------------------------------
default:
{
}
break;
}
}
}
//=================================================
static void synthesizer(sys_st *sys)
{
int choice = 0;
cariboulite_radio_state_st *radio_hi = &sys->radio_high;
double current_freq = 100000000.0;
bool active = false;
bool lock = false;
//cariboulite_radio_set_cw_outputs(radio_hi, false, false);
//cariboulite_radio_activate_channel(radio_hi, cariboulite_channel_dir_tx, false);
caribou_fpga_set_io_ctrl_mode (&radio_hi->sys->fpga, 0, caribou_fpga_io_ctrl_rfm_tx_lowpass);
cariboulite_radio_ext_ref (radio_hi->sys, cariboulite_ext_ref_32mhz);
rffc507x_set_frequency(&radio_hi->sys->mixer, current_freq);
lock = cariboulite_radio_wait_mixer_lock(radio_hi, 10);
rffc507x_calibrate(&radio_hi->sys->mixer);
while (1)
{
printf(" Parameters:\n");
printf(" [1] Set Frequency (%.5f MHz, LOCKED=%d)\n", current_freq / 1e6, lock);
printf(" [2] Activate [%s]\n", active?"Active":"Not Active");
printf(" [99] Return to main menu\n");
printf(" Choice: ");
if (scanf("%d", &choice) != 1) continue;
switch (choice)
{
//--------------------------------------------
case 1:
{
printf(" Enter frequency [Hz]: ");
if (scanf("%lf", &current_freq) != 1) continue;
if (current_freq < 2400e6) caribou_fpga_set_io_ctrl_mode (&radio_hi->sys->fpga, 0, caribou_fpga_io_ctrl_rfm_tx_lowpass);
else caribou_fpga_set_io_ctrl_mode (&radio_hi->sys->fpga, 0, caribou_fpga_io_ctrl_rfm_tx_hipass);
double act_freq = rffc507x_set_frequency(&radio_hi->sys->mixer, current_freq);
lock = cariboulite_radio_wait_mixer_lock(radio_hi, 10);
if (active)
{
rffc507x_output_lo(&radio_hi->sys->mixer, active);
}
current_freq = act_freq;
}
break;
//--------------------------------------------
case 2:
{
active = !active;
rffc507x_output_lo(&radio_hi->sys->mixer, active);
}
break;
//--------------------------------------------
case 99:
active = false;
rffc507x_output_lo(&radio_hi->sys->mixer, false);
cariboulite_radio_set_cw_outputs(radio_hi, false, false);
caribou_fpga_set_io_ctrl_mode (&radio_hi->sys->fpga, 0, caribou_fpga_io_ctrl_rfm_bypass);
return;
//--------------------------------------------
default:
{
}
break;
}
}
}
//=================================================
int app_menu(sys_st* sys)
{
printf("\n");
printf(" ____ _ _ _ _ _ \n");
printf(" / ___|__ _ _ __(_) |__ ___ _ _| | (_) |_ ___ \n");
printf(" | | / _` | '__| | '_ \\ / _ \\| | | | | | | __/ _ \\ \n");
printf(" | |__| (_| | | | | |_) | (_) | |_| | |___| | || __/ \n");
printf(" \\____\\__,_|_| |_|_.__/ \\___/ \\__,_|_____|_|\\__\\___| \n");
printf("\n\n");
while (1)
{
int choice = -1;
printf(" Select a function:\n");
for (int i = 0; i < NUM_HANDLES; i++)
{
printf(" [%d] %s\n", handles[i].num, handles[i].text);
}
printf(" [%d] %s\n", app_selection_quit, "Quit");
printf(" Choice: ");
if (scanf("%d", &choice) != 1) continue;
if ((app_selection_en)(choice) == app_selection_quit) return 0;
for (int i = 0; i < NUM_HANDLES; i++)
{
if (handles[i].num == (app_selection_en)(choice))
{
if (handles[i].handle != NULL)
{
printf("\n=====================================\n");
handles[i].handle(sys);
printf("\n=====================================\n");
}
else
{
printf(" Choice %d is not implemented\n", choice);
}
}
}
}
return 1;
}

Wyświetl plik

@ -1,2 +0,0 @@
# build directories
build

Wyświetl plik

@ -1,24 +0,0 @@
cmake_minimum_required(VERSION 3.15)
project(cariboulite)
set(CMAKE_BUILD_TYPE Release)
#Bring the headers, such as Student.h into the project
set(SUPER_DIR ${PROJECT_SOURCE_DIR}/..)
include_directories(/.)
include_directories(${SUPER_DIR})
#However, the file(GLOB...) allows for wildcard additions:
set(SOURCES_LIB at86rf215.c at86rf215_events.c at86rf215_radio.c at86rf215_baseband.c)
set(SOURCES ${SOURCES_LIB} test_at86rf215.c)
set(EXTERN_LIBS ${SUPER_DIR}/io_utils/build/libio_utils.a ${SUPER_DIR}/zf_log/build/libzf_log.a -lpthread)
#add_compile_options(-Wall -Wextra -pedantic -Werror)
add_compile_options(-Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -Wno-missing-braces)
#Generate the static library from the sources
add_library(at86rf215 STATIC ${SOURCES_LIB})
#add_executable(test_at86rf215 ${SOURCES})
#target_link_libraries(test_at86rf215 rt pthread ${EXTERN_LIBS})
#Set the location for library installation -- i.e., /usr/lib in this case
# not really necessary in this example. Use "sudo make install" to apply
install(TARGETS at86rf215 DESTINATION /usr/lib)

Wyświetl plik

@ -1,771 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "AT86RF215_Main"
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "zf_log/zf_log.h"
#include "at86rf215.h"
#include "io_utils/io_utils.h"
#include "io_utils/io_utils_spi.h"
#include "at86rf215_radio.h"
#include "at86rf215_regs.h"
//===================================================================
int at86rf215_write_buffer(at86rf215_st* dev, uint16_t addr, uint8_t *buffer, uint8_t size )
{
// a maximal possible chunk size - 256 + 2(addr)
uint8_t chunk_tx[258] = {0};
uint8_t chunk_rx[258] = {0};
chunk_tx[0] = ((addr >> 8) & 0x3F) | 0x80;
chunk_tx[1] = addr & 0xFF;
memcpy(chunk_tx + 2, buffer, size);
return io_utils_spi_transmit(dev->io_spi, dev->io_spi_handle, chunk_tx, chunk_rx, size + 2, io_utils_spi_read_write);
}
//===================================================================
int at86rf215_read_buffer(at86rf215_st* dev, uint16_t addr, uint8_t *buffer, uint8_t size)
{
// a maximal possible chunk size - 256 + 2(addr)
uint8_t chunk_tx[258] = {0};
uint8_t chunk_rx[258] = {0};
chunk_tx[0] = (addr >> 8) & 0x3F;
chunk_tx[1] = addr & 0xFF;
int ret = io_utils_spi_transmit(dev->io_spi, dev->io_spi_handle, chunk_tx, chunk_rx, size + 2, io_utils_spi_read_write);
if (ret == 0)
{
memcpy(buffer, chunk_rx + 2, size);
}
return ret;
}
//===================================================================
int at86rf215_write_byte(at86rf215_st* dev, uint16_t addr, uint8_t val )
{
uint8_t chunk_tx[3] = {0};
uint8_t chunk_rx[3] = {0};
chunk_tx[0] = ((addr >> 8) & 0x3F) | 0x80;
chunk_tx[1] = addr & 0xFF;
chunk_tx[2] = val;
return io_utils_spi_transmit(dev->io_spi, dev->io_spi_handle,
chunk_tx, chunk_rx, 3, io_utils_spi_read_write);
}
//===================================================================
int at86rf215_read_byte(at86rf215_st* dev, uint16_t addr)
{
uint8_t chunk_tx[3] = {0};
uint8_t chunk_rx[3] = {0};
chunk_tx[0] = (addr >> 8) & 0x3F;
chunk_tx[1] = addr & 0xFF;
/*printf("TX: ");
for (int i = 0; i < 3; i ++)
printf(" 0x%02X ", chunk_tx[i]);
printf("\n");*/
int ret = io_utils_spi_transmit(dev->io_spi, dev->io_spi_handle,
chunk_tx, chunk_rx, 3, io_utils_spi_read_write);
if (ret < 0)
{
return ret;
}
/*printf("RX: ");
for (int i = 0; i < 3; i ++)
printf(" 0x%02X ", chunk_rx[i]);
printf("\n");*/
return chunk_rx[2];
}
//===================================================================
#define NUM_CAL_STEPS 5
void swap(int *p,int *q)
{
int t;
t=*p;
*p=*q;
*q=t;
}
void sort(int a[],int n)
{
int i,j,temp;
for(i = 0;i < n-1;i++) {
for(j = 0;j < n-i-1;j++) {
if(a[j] > a[j+1])
swap(&a[j],&a[j+1]);
}
}
}
int median(int a[], int n)
{
if (n==0) return 0;
sort(a,n);
return a[(n+1)/2-1];
}
//===================================================================
int at86rf215_calibrate_device(at86rf215_st* dev, at86rf215_rf_channel_en ch, int* i_val, int* q_val)
{
int cal_i[NUM_CAL_STEPS] = {0};
int cal_q[NUM_CAL_STEPS] = {0};
bool override_flag = dev->override_cal;
dev->override_cal = false;
ZF_LOGD("Calibration of modem channel %d...", ch);
for (int i = 0; i < NUM_CAL_STEPS; i ++)
{
at86rf215_radio_set_state(dev, ch, at86rf215_radio_state_cmd_trx_off);
io_utils_usleep(2000);
at86rf215_radio_set_state(dev, ch, at86rf215_radio_state_cmd_tx_prep);
io_utils_usleep(10000);
at86rf215_radio_get_tx_iq_calibration(dev, ch, &cal_i[i], &cal_q[i]);
//printf("[%d,%d], ", cal_i[i], cal_q[i]);
}
// medians
int cal_i_med = median(cal_i, NUM_CAL_STEPS);
int cal_q_med = median(cal_q, NUM_CAL_STEPS);
ZF_LOGD("Calibration Results of the modem: I=%d, Q=%d", cal_i_med, cal_q_med);
if (i_val) *i_val = cal_i_med;
if (q_val) *q_val = cal_q_med;
if (ch == at86rf215_rf_channel_900mhz)
{
dev->cal.low_ch_i = cal_i_med;
dev->cal.low_ch_q = cal_q_med;
}
if (ch == at86rf215_rf_channel_2400mhz)
{
dev->cal.hi_ch_i = cal_i_med;
dev->cal.hi_ch_q = cal_q_med;
}
dev->override_cal = override_flag;
return 0;
}
//===================================================================
int at86rf215_init(at86rf215_st* dev,
io_utils_spi_st* io_spi)
{
if (dev == NULL)
{
ZF_LOGE("dev is NULL");
return -1;
}
dev->io_spi = io_spi;
ZF_LOGD("configuring reset and irq pins");
// Configure GPIO pins
io_utils_setup_gpio(dev->reset_pin, io_utils_dir_output, io_utils_pull_off);
io_utils_setup_gpio(dev->irq_pin, io_utils_dir_input, io_utils_pull_up);
// set to known state
io_utils_write_gpio(dev->reset_pin, 1);
ZF_LOGD("Adding chip definition to io_utils_spi");
io_utils_hard_spi_st hard_dev_modem = { .spi_dev_id = dev->spi_dev, .spi_dev_channel = dev->spi_channel, };
dev->io_spi_handle = io_utils_spi_add_chip(dev->io_spi, dev->cs_pin, 1000000, 0, 0,
io_utils_spi_chip_type_modem,
&hard_dev_modem);
// Setup the interrupts after clearing the register one time
at86rf215_irq_st irq = {0};
at86rf215_get_irqs(dev, &irq, 0);
dev->num_interrupts = 0;
if (io_utils_setup_interrupt(dev->irq_pin, at86rf215_interrupt_handler, dev) < 0)
{
ZF_LOGE("interrupt registration for irq_pin (%d) failed", dev->irq_pin);
//io_utils_setup_gpio(dev->reset_pin, io_utils_dir_input, io_utils_pull_up);
io_utils_setup_gpio(dev->irq_pin, io_utils_dir_input, io_utils_pull_up);
io_utils_spi_remove_chip(dev->io_spi, dev->io_spi_handle);
return -1;
}
// Initialize events
event_node_init(&dev->events.lo_trx_ready_event);
event_node_init(&dev->events.lo_energy_measure_event);
event_node_init(&dev->events.hi_trx_ready_event);
event_node_init(&dev->events.hi_energy_measure_event);
// Get chip type
uint8_t pn = 0, vn = 0;
at86rf215_get_versions(dev, &pn, &vn);
ZF_LOGD("Modem identity: Version: %02X, Product: %02X", vn, pn);
// calibrate TXPREP
at86rf215_calibrate_device(dev, at86rf215_rf_channel_900mhz, &dev->cal.low_ch_i, &dev->cal.low_ch_q);
at86rf215_calibrate_device(dev, at86rf215_rf_channel_2400mhz, &dev->cal.hi_ch_i, &dev->cal.hi_ch_q);
dev->override_cal = true;
dev->initialized = 1;
return 0;
}
//===================================================================
int at86rf215_close(at86rf215_st* dev)
{
if (dev == NULL)
{
ZF_LOGE("device pointer NULL");
return -1;
}
if (!dev->initialized)
{
ZF_LOGE("device not initialized");
return 0;
}
dev->initialized = 0;
event_node_close(&dev->events.lo_trx_ready_event);
event_node_close(&dev->events.lo_energy_measure_event);
event_node_close(&dev->events.hi_trx_ready_event);
event_node_close(&dev->events.hi_energy_measure_event);
//io_utils_setup_gpio(dev->reset_pin, io_utils_dir_input, io_utils_pull_up);
io_utils_setup_gpio(dev->irq_pin, io_utils_dir_input, io_utils_pull_up);
// Release the SPI device
io_utils_spi_remove_chip(dev->io_spi, dev->io_spi_handle);
ZF_LOGD("device release completed");
return 0;
}
//===================================================================
void at86rf215_reset(at86rf215_st* dev)
{
io_utils_write_gpio(dev->reset_pin, 0);
io_utils_usleep(300);
io_utils_write_gpio(dev->reset_pin, 1);
}
//===================================================================
void at86rf215_chip_reset_with_spi(at86rf215_st* dev)
{
uint8_t val = 0x7;
at86rf215_write_byte(dev, REG_RF_RST, val);
}
//===================================================================
void at86rf215_get_versions(at86rf215_st* dev, uint8_t *pn, uint8_t *vn)
{
if (pn) *pn = at86rf215_read_byte(dev, REG_RF_PN);
if (vn) *vn = at86rf215_read_byte(dev, REG_RF_VN);
}
//===================================================================
int at86rf215_print_version(at86rf215_st* dev)
{
uint8_t pn = 0, vn = 0;
at86rf215_get_versions(dev, &pn, &vn);
//at86rf215_get_versions(dev, &pn, &vn);
if (pn == at86rf215_pn_at86rf215) // 0x34
{
ZF_LOGD("MODEM Version: AT86RF215 (with basebands), version: %02x", vn);
}
else if (pn == at86rf215_pn_at86rf215iq) // 0x35
{
ZF_LOGD("MODEM Version: AT86RF215IQ (without basebands), version: %02x", vn);
}
else
{
ZF_LOGW("MODEM Version: not AT86RF215 IQ capable modem (product number: 0x%02x, versions %02x)", pn, vn);
}
return pn;
}
//===================================================================
int at86rf215_write_fifo(at86rf215_st* dev, uint8_t *buffer, uint8_t size )
{
return at86rf215_write_buffer(dev, 0, buffer, size);
}
//===================================================================
int at86rf215_read_fifo(at86rf215_st* dev, uint8_t *buffer, uint8_t size )
{
return at86rf215_read_buffer(dev, 0, buffer, size);
}
//===================================================================
void at86rf215_set_clock_output(at86rf215_st* dev,
at86rf215_drive_current_en drv_level,
at86rf215_clock_out_freq_en clock_val)
{
uint8_t val = ( (drv_level&0x03)<<3 ) | (clock_val&0x07);
at86rf215_write_byte(dev, REG_RF_CLKO, val);
}
//===================================================================
void at86rf215_setup_rf_irq(at86rf215_st* dev, uint8_t active_low,
uint8_t show_masked_irq,
at86rf215_drive_current_en drive)
{
uint8_t val = 0;
val |= (show_masked_irq&0x1)<<3;
val |= (active_low&0x1)<<2;
val |= (drive&0x3);
at86rf215_write_byte(dev, REG_RF_CFG, val);
}
//===================================================================
static void at86rf215_print_radio_irq(at86rf215_radio_irq_st* irq)
{
printf(" IQ_if_sync_fail: %d\n", irq->IQ_if_sync_fail);
printf(" trx_error: %d\n", irq->trx_error);
printf(" battery_low: %d\n", irq->battery_low);
printf(" energy_detection_complete: %d\n", irq->energy_detection_complete);
printf(" trx_ready: %d\n", irq->trx_ready);
printf(" wake_up_por: %d\n", irq->wake_up_por);
}
//===================================================================
static void at86rf215_print_bb_irq(at86rf215_baseband_irq_st* irq)
{
printf(" frame_buffer_level: %d\n", irq->frame_buffer_level);
printf(" agc_release: %d\n", irq->agc_release);
printf(" agc_hold: %d\n", irq->agc_hold);
printf(" frame_tx_complete: %d\n", irq->frame_tx_complete);
printf(" frame_rx_match_extended: %d\n", irq->frame_rx_match_extended);
printf(" frame_rx_address_match: %d\n", irq->frame_rx_address_match);
printf(" frame_rx_complete: %d\n", irq->frame_rx_complete);
printf(" frame_rx_started: %d\n", irq->frame_rx_started);
}
//===================================================================
void at86rf215_get_irqs(at86rf215_st* dev, at86rf215_irq_st* irq, int verbose)
{
at86rf215_read_buffer(dev, REG_RF09_IRQS, (uint8_t*)irq, 4);
if (verbose)
{
printf("IRQ Status:\n");
printf(" Radio09:\n"); at86rf215_print_radio_irq(&irq->radio09);
printf(" Radio24:\n"); at86rf215_print_radio_irq(&irq->radio24);
printf(" Baseband09:\n"); at86rf215_print_bb_irq(&irq->bb0);
printf(" Baseband24:\n"); at86rf215_print_bb_irq(&irq->bb1);
}
}
//===================================================================
void at86rf215_set_xo_trim(at86rf215_st* dev, uint8_t fast_start, float cap_trim)
{
if (cap_trim < 0.0f) cap_trim = 0.0f;
if (cap_trim > 4.5f) cap_trim = 4.5f;
uint8_t trim_val = ((uint8_t)((cap_trim+0.1f)/0.3f))&0xF;
trim_val |= (fast_start&0x1)<<4;
at86rf215_write_byte(dev, REG_RF_XOC, trim_val);
}
//===================================================================
void at86rf215_get_iq_if_cfg(at86rf215_st* dev, at86rf215_iq_interface_config_st* cfg, int verbose)
{
uint8_t data[3] = {0};
at86rf215_read_buffer(dev, REG_RF_IQIFC0, data, 3);
cfg->loopback_enable = (data[0]>>7)&0x01;
cfg->synchronization_failed = (data[0]>>6)&0x01;
cfg->drv_strength = (data[0]>>4)&0x03;
uint8_t cmv = (data[0]>>2)&0x03;
cfg->common_mode_voltage = ((data[0]>>1)&0x01)?at86rf215_iq_common_mode_v_ieee1596_1v2:cmv;
cfg->tx_control_with_iq_if = (data[0]>>0)&0x01;
cfg->in_failsafe_mode = (data[1]>>7)&0x01;
uint8_t chip_mode = (data[1]>>4)&0x07;
switch (chip_mode)
{
case 0x00:
cfg->radio09_mode = at86rf215_baseband_mode;
cfg->radio24_mode = at86rf215_baseband_mode;
break;
case 0x01:
cfg->radio09_mode = at86rf215_iq_if_mode;
cfg->radio24_mode = at86rf215_iq_if_mode;
break;
case 0x04:
cfg->radio09_mode = at86rf215_iq_if_mode;
cfg->radio24_mode = at86rf215_baseband_mode;
break;
case 0x05:
cfg->radio09_mode = at86rf215_baseband_mode;
cfg->radio24_mode = at86rf215_iq_if_mode;
break;
default:
ZF_LOGE("I/Q chipmode invalid: %d", chip_mode);
break;
}
cfg->clock_skew = (data[1]>>0)&0x03;
cfg->synchronized_incoming_iq = (data[2]>>7)&0x01;
if (verbose)
{
printf("Current I/Q interface settings:\n");
printf(" Loopback (RX => TX): %s\n", cfg->loopback_enable?"enabled":"disabled");
printf(" Drive strength: %d mA\n", cfg->drv_strength+1);
if (cfg->common_mode_voltage == at86rf215_iq_common_mode_v_ieee1596_1v2)
{
printf(" Common mode voltage: %.1f V\n", 1.2f);
}
else
{
printf(" Common mode voltage: %d mV\n", (cfg->common_mode_voltage+1) * 50 + 100);
}
printf(" I/Q interface for sub-GHz: %s\n", cfg->radio09_mode==at86rf215_iq_if_mode?"enabled":"diabled");
printf(" I/Q interface for 2.4-GHz: %s\n", cfg->radio24_mode==at86rf215_iq_if_mode?"enabled":"diabled");
printf(" I/Q Clock <=> Data skew: %.3f ns\n", cfg->clock_skew+1.906f);
printf(" Status 'Sync Failure': %d\n", cfg->synchronization_failed);
printf(" Status 'Failsafe mode': %d\n", cfg->in_failsafe_mode);
printf(" Status 'Is synchronized to incoming I/Q': %d\n", cfg->synchronized_incoming_iq);
}
}
//===================================================================
void at86rf215_setup_iq_if(at86rf215_st* dev, at86rf215_iq_interface_config_st* cfg)
{
uint8_t data[2] = {0};
data[0] |= (cfg->loopback_enable&0x01) << 7;
data[0] |= (cfg->drv_strength&0x03) << 4;
if (cfg->common_mode_voltage == at86rf215_iq_common_mode_v_ieee1596_1v2)
{
data[0] |= 1<<1;
}
else
{
data[0] |= (cfg->common_mode_voltage & 0x3) << 2;
}
data[0] |= (cfg->tx_control_with_iq_if & 0x01) << 0;
if (cfg->radio09_mode == at86rf215_iq_if_mode && cfg->radio24_mode == at86rf215_iq_if_mode)
{
data[1] |= 0x01 << 4;
}
else if (cfg->radio09_mode == at86rf215_iq_if_mode && cfg->radio24_mode == at86rf215_baseband_mode)
{
data[1] |= 0x04 << 4;
}
else if (cfg->radio09_mode == at86rf215_baseband_mode && cfg->radio24_mode == at86rf215_iq_if_mode)
{
data[1] |= 0x05 << 4;
}
data[1] |= (cfg->clock_skew & 0x03) << 0;
at86rf215_write_buffer(dev, REG_RF_IQIFC0, data, 2);
}
//===================================================================
double at86rf215_check_freq (at86rf215_st* dev, at86rf215_rf_channel_en ch, uint64_t freq_hz )
{
at86rf215_radio_channel_mode_en mode = 0;
at86rf215_rf_channel_en req_ch = 0;
if (at86rf215_radio_get_good_channel(freq_hz, &mode, &req_ch) < 0 || req_ch != ch)
{
ZF_LOGE("the requested channel or frequency not supported");
return -1;
}
int center_freq_25khz_res = 0;
int channel_number = 0;
double actual_freq = at86rf215_radio_get_frequency(mode, 1, freq_hz, &center_freq_25khz_res, &channel_number);
return actual_freq;
}
//===================================================================
int64_t at86rf215_setup_channel ( at86rf215_st* dev, at86rf215_rf_channel_en ch, uint64_t freq_hz )
{
if (dev->initialized == 0)
{
ZF_LOGE("device not initialized");
return -1;
}
at86rf215_radio_channel_mode_en mode = 0;
at86rf215_rf_channel_en req_ch = 0;
if (at86rf215_radio_get_good_channel(freq_hz, &mode, &req_ch) < 0 || req_ch != ch)
{
ZF_LOGE("the requested channel or frequency not supported");
return -1;
}
int center_freq_25khz_res = 0;
int channel_number = 0;
double actual_freq = at86rf215_radio_get_frequency(mode, 1, freq_hz, &center_freq_25khz_res, &channel_number);
at86rf215_radio_setup_channel(dev, ch, 1, center_freq_25khz_res, channel_number, mode);
return (int64_t)actual_freq;
}
//===================================================================
void at86rf215_setup_iq_radio_transmit (at86rf215_st* dev, at86rf215_rf_channel_en radio)
{
/*
It is assumed, that the radio has been reset before and is in State TRXOFF. All interrupts in register RFn_IRQS should be enabled (RFn_IRQM=0x3f).
*/
// 1. Set TRXOFF mode
// 2. Enable all interrupts in 09,_24_IRQS
// 3. Enable I/Q radio mode - setting IQIFC1.CHPM=1 at AT86RF215
// 4. Configure the Transmitter Frontend:
// Set the transmitter analog frontend sub-registers TXCUTC.LPFCUT and TXCUTC.PARAMP
// Set the transmitter digital frontend sub-registers TXDFE.SR and TXDFE.RCUT
// 5. Configure the channel parameters, see section "Channel Configuration" on page 62 and transmit power
// 6. Optional: Perform ED measurement, see section "Energy Measurement" on page 56. The following steps are recommended:
// Configure the measurement period, see register RFn_EDD.
// Switch to State RX.
// Start and finish a measurement:
// For single and continuous ED modes a measurement starts if the mode is written to sub-register EDC.EDM.
// The completion of the measurement is indicated by the interrupt IRQS.EDC. The resulting ED value can be read from register RFn_EDV.
// For the automatic mode, a measurement starts by setting bit AGCC.FRZC=1. After the completion of the measurement period, the ED value can be read from register RFn_EDV.
// 7. Switch to State TXPREP; interrupt IRQS.TRXRDY is issued.
// 8. To start the actual transmission, there are two possibilities, depending on the setting of sub-register IQIFC0.EEC:
// IQIFC0.EEC=0 => Enable the radio transmitter by writing command TX to the register RFn_CMD via SPI.
// IQIFC0.EEC=1 => The transmitter is activated automatically with the TX start signal embedded in I_DATA[0],
// 9. To finish a transmission depends on the setting of bit IQIFC0.EEC:
// IQIFC0.EEC=0 => To leave the State TX, write command TXPREP to the register RFn_CMD. Reaching State TXPREP is indicated by the interrupt IRQS.TRXRDY.
// IQIFC0.EEC=1 => If the bit I_DATA[0] is set to 0 (see Figure 6-4 on page 47) the ramp down process of the PA is started automatically. After ramp down the transmitter switches back to State TXPREP.
}
//===================================================================
void at86rf215_setup_iq_radio_receive (at86rf215_st* dev, at86rf215_rf_channel_en radio, uint64_t freq_hz,
int iqloopback, at86rf215_iq_clock_data_skew_en skew)
{
/*
It is assumed, that
1. the radio has been reset before and is in State TRXOFF.
2. All interrupts in register RFn_IRQS should be enabled (RFn_IRQM=0x3f).
*/
// 1. Set TRXOFF mode
at86rf215_radio_set_state(dev, radio, at86rf215_radio_state_cmd_trx_off);
// 2. Enable all radio interrupts in 09,_24_IRQS
at86rf215_radio_irq_st int_mask = {
.wake_up_por = 1,
.trx_ready = 1,
.energy_detection_complete = 1,
.battery_low = 1,
.trx_error = 1,
.IQ_if_sync_fail = 1,
.res = 0,
};
at86rf215_radio_setup_interrupt_mask(dev, radio, &int_mask);
// 3. Enable I/Q radio mode - setting IQIFC1.CHPM=1 at AT86RF215 (in AT86RF215IQ it is the only choice)
at86rf215_iq_interface_config_st iq_if_config =
{
.loopback_enable = iqloopback,
.drv_strength = at86rf215_iq_drive_current_4ma,
.common_mode_voltage = at86rf215_iq_common_mode_v_ieee1596_1v2,
.tx_control_with_iq_if = false,
.radio09_mode = at86rf215_iq_if_mode,
.radio24_mode = at86rf215_iq_if_mode,
.clock_skew = skew,
};
at86rf215_setup_iq_if(dev, &iq_if_config);
// 4. Configure the Receiving Frontend:
// Set the receiver analog frontend sub-registers RXBWC.BW and RXBWC.IFS,
// Set the receiver digital frontend sub-registers RXDFE.SR and RXDFE.RCUT
// Set the AGC registers RFn_AGCC and RFn_AGCS
at86rf215_radio_set_rx_bw_samp_st rx_bw_samp_cfg =
{
.inverter_sign_if = 0, // A value of one configures the receiver to implement the inverted-sign IF freq.
.shift_if_freq = 0, // A value of one configures the receiver to shift the IF frequency by factor of 1.25.
.bw = at86rf215_radio_rx_bw_BW2000KHZ_IF2000KHZ,
// The sub-register controls the receiver filter bandwidth settings.
.fcut = at86rf215_radio_rx_f_cut_half_fs,
// RX filter relative cut-off frequency
.fs = at86rf215_radio_rx_sample_rate_4000khz,
// RX Sample Rate
};
at86rf215_radio_set_rx_bandwidth_sampling(dev, radio, &rx_bw_samp_cfg);
at86rf215_radio_agc_ctrl_st agc_ctrl =
{
// commands
.agc_measure_source_not_filtered = 0, // AGC Input (0 - filterred, 1 - unfiltered, faster operation)
.avg = at86rf215_radio_agc_averaging_8, // AGC Average Time in Number of Samples
.reset_cmd = 0, // AGC Reset - resets the AGC and sets the maximum receiver gain.
.freeze_cmd = 0, // AGC Freeze Control - A value of one forces the AGC to
// freeze to its current value.
.enable_cmd = 1, // AGC Enable - a value of zero allows a manual setting of
// the RX gain control by sub-register AGCS.GCW
.att = at86rf215_radio_agc_relative_atten_21_db,// AGC Target Level - sets the AGC target level relative to ADC full scale.
.gain_control_word = 0, // If AGCC_EN is set to 1, a read of bit AGCS.GCW indicates the current
// receiver gain setting. If AGCC_EN is set to 0, a write access to GCW
// manually sets the receiver gain. An integer value of 23 indicates
// the maximum receiver gain; each integer step changes the gain by 3dB.
.freeze_status = 0, // AGC Freeze Status - A value of one indicates that the AGC is on hold.
};
at86rf215_radio_setup_agc(dev, radio, &agc_ctrl);
// 5. Configure the channel parameters, see section "Channel Configuration" on page 62 and transmit power
at86rf215_setup_channel (dev, radio, freq_hz);
// 6. Switch to State TXPREP; interrupt IRQS.TRXRDY is issued.
// TXD and TXCLK are activated as shown in Figure 4-12 on page 26.
// What? Why TX?
// 7. Prepare the external baseband for reception of I/Q samples
// The FPGA was born prepared (;
// 8. Enable the radio receiver by writing command RX to the register RFn_CMD.
at86rf215_radio_set_state(dev, radio, at86rf215_radio_state_cmd_rx);
// 9. To prevent the AGC from switching its gain during reception, it is recommended to set AGCC.FRZC=1
// after reception of the preamble, the AGC has to be released after finishing reception by setting AGCC.FRZC=0.
// at86rf215_radio_setup_agc(dev, radio, &agc_ctrl);
}
//===================================================================
void at86rf215_stop_iq_radio_receive (at86rf215_st* dev, at86rf215_rf_channel_en radio)
{
at86rf215_radio_set_state(dev, radio, at86rf215_radio_state_cmd_trx_off);
at86rf215_iq_interface_config_st iq_if_config =
{
.loopback_enable = 0,
.drv_strength = at86rf215_iq_drive_current_2ma,
.common_mode_voltage = at86rf215_iq_common_mode_v_ieee1596_1v2,
.tx_control_with_iq_if = false,
.radio09_mode = at86rf215_baseband_mode,
.radio24_mode = at86rf215_baseband_mode,
.clock_skew = at86rf215_iq_clock_data_skew_4_906ns,
};
at86rf215_setup_iq_if(dev, &iq_if_config);
}
//===================================================================
void at86rf215_setup_iq_radio_continues_tx (at86rf215_st* dev, at86rf215_rf_channel_en ch)
{
// This is useful for application / production tests as well as certification tests.
// Using this mode, the transceiver acts as a continuous transmitter
// 1. Prior to transmission, the AT86RF215 must be in state TXPREP, see section "State Machine" on page 33.
// 2. The continuous transmission is enabled if the sub-register PC.CTX is set to 1
// 3. A frame transmission, started by CMD.CMD=TX with enabled continuous transmit mode (PC.CTX),
// transmits synchronization header (SHR), PHY header (PHR) and repeatedly PHY payload (PSDU).
// 4. The current PHY settings are used
// 5. the length of the PHY payload is configured by the concatenation of the registers BBCn_TXFLH and BBCn_TXFLL.
// If the sub-register PC.TXAFCS is set to 1, the last PHY payload octets are replaced by the calculated FCS
// 6. The transmission proceeds as long as the sub-register PC.CTX remains 1. If the sub-register PC.CTX is set
// to 0, the transmission stops once the current PSDU transmission is completed
}
void at86rf215_setup_iq_radio_dac_value_override_no_freq (at86rf215_st* dev,
at86rf215_rf_channel_en ch,
uint8_t tx_power)
{
at86rf215_radio_state_cmd_en state = at86rf215_radio_get_state(dev, ch);
if (state != at86rf215_radio_state_cmd_trx_off)
{
at86rf215_radio_set_state(dev, ch, at86rf215_radio_state_cmd_trx_off);
}
at86rf215_radio_set_state(dev, ch, at86rf215_radio_state_cmd_tx_prep);
at86rf215_radio_tx_ctrl_st tx_config =
{
.pa_ramping_time = at86rf215_radio_tx_pa_ramp_32usec,
.current_reduction = at86rf215_radio_pa_current_reduction_0ma,
.tx_power = tx_power,
.analog_bw = at86rf215_radio_tx_cut_off_80khz,
.digital_bw = at86rf215_radio_rx_f_cut_half_fs,
.fs = at86rf215_radio_rx_sample_rate_4000khz,
.direct_modulation = 0,
};
at86rf215_radio_setup_tx_ctrl(dev, ch, &tx_config);
at86rf215_radio_set_tx_dac_input_iq(dev, ch, 1, 0x7E, 1, 0x3F);
at86rf215_radio_set_state(dev, ch, at86rf215_radio_state_cmd_tx);
}
void at86rf215_setup_iq_radio_dac_value_override (at86rf215_st* dev,
at86rf215_rf_channel_en ch,
uint32_t freq_hz,
uint8_t tx_power)
{
// The AT86RF215 comprises a DAC (digital to analog converter) value overwrite functionality.
// Each transceiver contains two transmitter DACs in order to transmit IQ signals. This feature is useful to
// transmit an LO carrier which is necessary for certain certifications.
// If the sub-register TXDACI.ENTXDACID is set to 1, the digital input value of the in-phase signal DAC is
// overwritten with the value of the sub-register TXDACI.TXDACID. The same with TXDACQ.ENTXDACQD and TXDACQ.TXDACQD.
// Both TXDACI.TXDACID and TXDACQ.TXDACQD contain 7-bit binary values in the range from 0x00 to 0x7E (dec. 126).
// 0x3F (63) is zero, 0x00 is the minimal signal, and 0x7E is the maximal signal.
// If the transceiver is in state TX and both DAC values are overwritten, the transceiver transmits an LO
// carrier of the frequency selected by the "Frequency Synthesizer (PLL)" on page 62.
// To start a continuous transmission of a LO carrier, the transmitter is started as described in
// (at86rf215_setup_iq_radio_continues_tx) Frame Based Continuous Transmission.
// Alternatively, the transmitter can be started using chip mode 1 if sub-register IQIFC1.CHPM is set to 0x01.
// (this is the case of I/Q over LVDS) In this case the transmitter is started by command TX.
at86rf215_radio_state_cmd_en state = at86rf215_radio_get_state(dev, ch);
if (state != at86rf215_radio_state_cmd_trx_off)
{
at86rf215_radio_set_state(dev, ch, at86rf215_radio_state_cmd_trx_off);
}
at86rf215_radio_set_state(dev, ch, at86rf215_radio_state_cmd_tx_prep);
at86rf215_radio_tx_ctrl_st tx_config =
{
.pa_ramping_time = at86rf215_radio_tx_pa_ramp_32usec,
.current_reduction = at86rf215_radio_pa_current_reduction_0ma,
.tx_power = tx_power,
.analog_bw = at86rf215_radio_tx_cut_off_80khz,
.digital_bw = at86rf215_radio_rx_f_cut_half_fs,
.fs = at86rf215_radio_rx_sample_rate_4000khz,
.direct_modulation = 0,
};
at86rf215_radio_setup_tx_ctrl(dev, ch, &tx_config);
at86rf215_radio_external_ctrl_st aux_cfg =
{
.ext_lna_bypass_available = 0,
.agc_backoff = 0,
.analog_voltage_external = 0,
.analog_voltage_enable_in_off = 0,
.int_power_amplifier_voltage = 2,
.fe_pad_configuration = 1,
};
at86rf215_radio_setup_external_settings(dev, ch, &aux_cfg);
at86rf215_iq_interface_config_st iq_if_config =
{
.loopback_enable = 0,
.drv_strength = at86rf215_iq_drive_current_2ma,
.common_mode_voltage = at86rf215_iq_common_mode_v_ieee1596_1v2,
.tx_control_with_iq_if = false,
.radio09_mode = at86rf215_iq_if_mode,
.radio24_mode = at86rf215_iq_if_mode,
.clock_skew = at86rf215_iq_clock_data_skew_4_906ns,
};
at86rf215_setup_iq_if(dev, &iq_if_config);
at86rf215_radio_set_tx_dac_input_iq(dev, ch, 1, 0x7E, 1, 0x3F);
at86rf215_setup_channel (dev, ch, freq_hz);
at86rf215_radio_set_state(dev, ch, at86rf215_radio_state_cmd_tx);
}

Wyświetl plik

@ -1,53 +0,0 @@
#ifndef __AT86RF215_H__
#define __AT86RF215_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "at86rf215_common.h"
#include "at86rf215_radio.h"
int at86rf215_init(at86rf215_st* dev,
io_utils_spi_st* io_spi);
int at86rf215_close(at86rf215_st* dev);
void at86rf215_reset(at86rf215_st* dev);
void at86rf215_get_versions(at86rf215_st* dev, uint8_t *pn, uint8_t *vn);
int at86rf215_print_version(at86rf215_st* dev);
void at86rf215_set_clock_output(at86rf215_st* dev,
at86rf215_drive_current_en drv_level,
at86rf215_clock_out_freq_en clock_val);
void at86rf215_setup_rf_irq(at86rf215_st* dev, uint8_t active_low,
uint8_t show_masked_irq,
at86rf215_drive_current_en drive);
void at86rf215_set_xo_trim(at86rf215_st* dev, uint8_t fast_start, float cap_trim);
void at86rf215_get_iq_if_cfg(at86rf215_st* dev, at86rf215_iq_interface_config_st* cfg, int verbose);
void at86rf215_setup_iq_if(at86rf215_st* dev, at86rf215_iq_interface_config_st* cfg);
void at86rf215_setup_iq_radio_transmit (at86rf215_st* dev, at86rf215_rf_channel_en radio);
void at86rf215_setup_iq_radio_receive(at86rf215_st *dev, at86rf215_rf_channel_en radio, uint64_t freq_hz,
int iqloopback, at86rf215_iq_clock_data_skew_en skew);
void at86rf215_stop_iq_radio_receive (at86rf215_st* dev, at86rf215_rf_channel_en radio);
void at86rf215_setup_iq_radio_continues_tx (at86rf215_st* dev, at86rf215_rf_channel_en radio);
void at86rf215_setup_iq_radio_dac_value_override (at86rf215_st* dev, at86rf215_rf_channel_en ch,
uint32_t freq_hz,
uint8_t tx_power );
void at86rf215_setup_iq_radio_dac_value_override_no_freq (at86rf215_st* dev,
at86rf215_rf_channel_en ch,
uint8_t tx_power);
int64_t at86rf215_setup_channel ( at86rf215_st* dev, at86rf215_rf_channel_en ch, uint64_t freq_hz );
double at86rf215_check_freq (at86rf215_st* dev, at86rf215_rf_channel_en ch, uint64_t freq_hz );
// EVENTS
void event_node_init(event_st* ev);
void event_node_close(event_st* ev);
void event_node_wait_ready(event_st* ev);
void event_node_signal_ready(event_st* ev, int ready);
#ifdef __cplusplus
}
#endif
#endif // __AT86RF215_H__

Wyświetl plik

@ -1,213 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "AT86RF215_BaseBand"
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "zf_log/zf_log.h"
#include "io_utils/io_utils.h"
#include "io_utils/io_utils_spi.h"
#include "at86rf215_radio.h"
#include "at86rf215_baseband.h"
#include "at86rf215_regs.h"
static const struct at86rf215_BBC_regs BBC0_regs = {
.RG_IRQS = 0x02,
.RG_FBRXS = 0x2000,
.RG_FBRXE = 0x27FE,
.RG_FBTXS = 0x2800,
.RG_FBTXE = 0x2FFE,
.RG_IRQM = 0x300,
.RG_PC = 0x301,
.RG_PS = 0x302,
.RG_RXFLL = 0x304,
.RG_RXFLH = 0x305,
.RG_TXFLL = 0x306,
.RG_TXFLH = 0x307,
.RG_FBLL = 0x308,
.RG_FBLH = 0x309,
.RG_FBLIL = 0x30A,
.RG_FBLIH = 0x30B,
.RG_OFDMPHRTX = 0x30C,
.RG_OFDMPHRRX = 0x30D,
.RG_OFDMC = 0x30E,
.RG_OFDMSW = 0x30F,
.RG_OQPSKC0 = 0x310,
.RG_OQPSKC1 = 0x311,
.RG_OQPSKC2 = 0x312,
.RG_OQPSKC3 = 0x313,
.RG_OQPSKPHRTX = 0x314,
.RG_OQPSKPHRRX = 0x315,
.RG_AFC0 = 0x320,
.RG_AFC1 = 0x321,
.RG_AFFTM = 0x322,
.RG_AFFVM = 0x323,
.RG_AFS = 0x324,
.RG_MACEA0 = 0x325,
.RG_MACEA1 = 0x326,
.RG_MACEA2 = 0x327,
.RG_MACEA3 = 0x328,
.RG_MACEA4 = 0x329,
.RG_MACEA5 = 0x32A,
.RG_MACEA6 = 0x32B,
.RG_MACEA7 = 0x32C,
.RG_MACPID0F0 = 0x32D,
.RG_MACPID1F0 = 0x32E,
.RG_MACSHA0F0 = 0x32F,
.RG_MACSHA1F0 = 0x330,
.RG_MACPID0F1 = 0x331,
.RG_MACPID1F1 = 0x332,
.RG_MACSHA0F1 = 0x333,
.RG_MACSHA1F1 = 0x334,
.RG_MACPID0F2 = 0x335,
.RG_MACPID1F2 = 0x336,
.RG_MACSHA0F2 = 0x337,
.RG_MACSHA1F2 = 0x338,
.RG_MACPID0F3 = 0x339,
.RG_MACPID1F3 = 0x33A,
.RG_MACSHA0F3 = 0x33B,
.RG_MACSHA1F3 = 0x33C,
.RG_AMCS = 0x340,
.RG_AMEDT = 0x341,
.RG_AMAACKPD = 0x342,
.RG_AMAACKTL = 0x343,
.RG_AMAACKTH = 0x344,
.RG_FSKC0 = 0x360,
.RG_FSKC1 = 0x361,
.RG_FSKC2 = 0x362,
.RG_FSKC3 = 0x363,
.RG_FSKC4 = 0x364,
.RG_FSKPLL = 0x365,
.RG_FSKSFD0L = 0x366,
.RG_FSKSFD0H = 0x367,
.RG_FSKSFD1L = 0x368,
.RG_FSKSFD1H = 0x369,
.RG_FSKPHRTX = 0x36A,
.RG_FSKPHRRX = 0x36B,
.RG_FSKRPC = 0x36C,
.RG_FSKRPCONT = 0x36D,
.RG_FSKRPCOFFT = 0x36E,
.RG_FSKRRXFLL = 0x370,
.RG_FSKRRXFLH = 0x371,
.RG_FSKDM = 0x372,
.RG_FSKPE0 = 0x373,
.RG_FSKPE1 = 0x374,
.RG_FSKPE2 = 0x375,
.RG_PMUC = 0x380,
.RG_PMUVAL = 0x381,
.RG_PMUQF = 0x382,
.RG_PMUI = 0x383,
.RG_PMUQ = 0x384,
.RG_CNTC = 0x390,
.RG_CNT0 = 0x391,
.RG_CNT1 = 0x392,
.RG_CNT2 = 0x393,
.RG_CNT3 = 0x394,
};
static const struct at86rf215_BBC_regs BBC1_regs = {
.RG_IRQS = 0x03,
.RG_FBRXS = 0x3000,
.RG_FBRXE = 0x37FE,
.RG_FBTXS = 0x3800,
.RG_FBTXE = 0x3FFE,
.RG_IRQM = 0x400,
.RG_PC = 0x401,
.RG_PS = 0x402,
.RG_RXFLL = 0x404,
.RG_RXFLH = 0x405,
.RG_TXFLL = 0x406,
.RG_TXFLH = 0x407,
.RG_FBLL = 0x408,
.RG_FBLH = 0x409,
.RG_FBLIL = 0x40A,
.RG_FBLIH = 0x40B,
.RG_OFDMPHRTX = 0x40C,
.RG_OFDMPHRRX = 0x40D,
.RG_OFDMC = 0x40E,
.RG_OFDMSW = 0x40F,
.RG_OQPSKC0 = 0x410,
.RG_OQPSKC1 = 0x411,
.RG_OQPSKC2 = 0x412,
.RG_OQPSKC3 = 0x413,
.RG_OQPSKPHRTX = 0x414,
.RG_OQPSKPHRRX = 0x415,
.RG_AFC0 = 0x420,
.RG_AFC1 = 0x421,
.RG_AFFTM = 0x422,
.RG_AFFVM = 0x423,
.RG_AFS = 0x424,
.RG_MACEA0 = 0x425,
.RG_MACEA1 = 0x426,
.RG_MACEA2 = 0x427,
.RG_MACEA3 = 0x428,
.RG_MACEA4 = 0x429,
.RG_MACEA5 = 0x42A,
.RG_MACEA6 = 0x42B,
.RG_MACEA7 = 0x42C,
.RG_MACPID0F0 = 0x42D,
.RG_MACPID1F0 = 0x42E,
.RG_MACSHA0F0 = 0x42F,
.RG_MACSHA1F0 = 0x430,
.RG_MACPID0F1 = 0x431,
.RG_MACPID1F1 = 0x432,
.RG_MACSHA0F1 = 0x433,
.RG_MACSHA1F1 = 0x434,
.RG_MACPID0F2 = 0x435,
.RG_MACPID1F2 = 0x436,
.RG_MACSHA0F2 = 0x437,
.RG_MACSHA1F2 = 0x438,
.RG_MACPID0F3 = 0x439,
.RG_MACPID1F3 = 0x43A,
.RG_MACSHA0F3 = 0x43B,
.RG_MACSHA1F3 = 0x43C,
.RG_AMCS = 0x440,
.RG_AMEDT = 0x441,
.RG_AMAACKPD = 0x442,
.RG_AMAACKTL = 0x443,
.RG_AMAACKTH = 0x444,
.RG_FSKC0 = 0x460,
.RG_FSKC1 = 0x461,
.RG_FSKC2 = 0x462,
.RG_FSKC3 = 0x463,
.RG_FSKC4 = 0x464,
.RG_FSKPLL = 0x465,
.RG_FSKSFD0L = 0x466,
.RG_FSKSFD0H = 0x467,
.RG_FSKSFD1L = 0x468,
.RG_FSKSFD1H = 0x469,
.RG_FSKPHRTX = 0x46A,
.RG_FSKPHRRX = 0x46B,
.RG_FSKRPC = 0x46C,
.RG_FSKRPCONT = 0x46D,
.RG_FSKRPCOFFT = 0x46E,
.RG_FSKRRXFLL = 0x470,
.RG_FSKRRXFLH = 0x471,
.RG_FSKDM = 0x472,
.RG_FSKPE0 = 0x473,
.RG_FSKPE1 = 0x474,
.RG_FSKPE2 = 0x475,
.RG_PMUC = 0x480,
.RG_PMUVAL = 0x481,
.RG_PMUQF = 0x482,
.RG_PMUI = 0x483,
.RG_PMUQ = 0x484,
.RG_CNTC = 0x490,
.RG_CNT0 = 0x491,
.RG_CNT1 = 0x492,
.RG_CNT2 = 0x493,
.RG_CNT3 = 0x494,
};
// BBCn_PC – PHY Control
// This register configures the baseband PHY.
void at86rf215_bb_set_phy_control (at86rf215_st *dev, at86rf215_rf_channel_en ch, at86rf215_bb_phy_control_st* pc)
{
}

Wyświetl plik

@ -1,212 +0,0 @@
#ifndef __AT86RF215_BASEBAND_H__
#define __AT86RF215_BASEBAND_H__
#ifdef __cplusplus
extern "C" {
#endif
struct at86rf215_BBC_regs
{
uint16_t RG_IRQS;
uint16_t RG_FBRXS;
uint16_t RG_FBRXE;
uint16_t RG_FBTXS;
uint16_t RG_FBTXE;
uint16_t RG_IRQM;
uint16_t RG_PC;
uint16_t RG_PS;
uint16_t RG_RXFLL;
uint16_t RG_RXFLH;
uint16_t RG_TXFLL;
uint16_t RG_TXFLH;
uint16_t RG_FBLL;
uint16_t RG_FBLH;
uint16_t RG_FBLIL;
uint16_t RG_FBLIH;
uint16_t RG_OFDMPHRTX;
uint16_t RG_OFDMPHRRX;
uint16_t RG_OFDMC;
uint16_t RG_OFDMSW;
uint16_t RG_OQPSKC0;
uint16_t RG_OQPSKC1;
uint16_t RG_OQPSKC2;
uint16_t RG_OQPSKC3;
uint16_t RG_OQPSKPHRTX;
uint16_t RG_OQPSKPHRRX;
uint16_t RG_AFC0;
uint16_t RG_AFC1;
uint16_t RG_AFFTM;
uint16_t RG_AFFVM;
uint16_t RG_AFS;
uint16_t RG_MACEA0;
uint16_t RG_MACEA1;
uint16_t RG_MACEA2;
uint16_t RG_MACEA3;
uint16_t RG_MACEA4;
uint16_t RG_MACEA5;
uint16_t RG_MACEA6;
uint16_t RG_MACEA7;
uint16_t RG_MACPID0F0;
uint16_t RG_MACPID1F0;
uint16_t RG_MACSHA0F0;
uint16_t RG_MACSHA1F0;
uint16_t RG_MACPID0F1;
uint16_t RG_MACPID1F1;
uint16_t RG_MACSHA0F1;
uint16_t RG_MACSHA1F1;
uint16_t RG_MACPID0F2;
uint16_t RG_MACPID1F2;
uint16_t RG_MACSHA0F2;
uint16_t RG_MACSHA1F2;
uint16_t RG_MACPID0F3;
uint16_t RG_MACPID1F3;
uint16_t RG_MACSHA0F3;
uint16_t RG_MACSHA1F3;
uint16_t RG_AMCS;
uint16_t RG_AMEDT;
uint16_t RG_AMAACKPD;
uint16_t RG_AMAACKTL;
uint16_t RG_AMAACKTH;
uint16_t RG_FSKC0;
uint16_t RG_FSKC1;
uint16_t RG_FSKC2;
uint16_t RG_FSKC3;
uint16_t RG_FSKC4;
uint16_t RG_FSKPLL;
uint16_t RG_FSKSFD0L;
uint16_t RG_FSKSFD0H;
uint16_t RG_FSKSFD1L;
uint16_t RG_FSKSFD1H;
uint16_t RG_FSKPHRTX;
uint16_t RG_FSKPHRRX;
uint16_t RG_FSKRPC;
uint16_t RG_FSKRPCONT;
uint16_t RG_FSKRPCOFFT;
uint16_t RG_FSKRRXFLL;
uint16_t RG_FSKRRXFLH;
uint16_t RG_FSKDM;
uint16_t RG_FSKPE0;
uint16_t RG_FSKPE1;
uint16_t RG_FSKPE2;
uint16_t RG_PMUC;
uint16_t RG_PMUVAL;
uint16_t RG_PMUQF;
uint16_t RG_PMUI;
uint16_t RG_PMUQ;
uint16_t RG_CNTC;
uint16_t RG_CNT0;
uint16_t RG_CNT1;
uint16_t RG_CNT2;
uint16_t RG_CNT3;
};
/** @} */
/** BPSK, rate ½, 4 x frequency repetition */
#define BB_MCS_BPSK_REP4 0
/** BPSK, rate ½, 2 x frequency repetition */
#define BB_MCS_BPSK_REP2 1
/** QPSK, rate ½, 2 x frequency repetition */
#define BB_MCS_QPSK_REP2 2
/** QPSK, rate ½ */
#define BB_MCS_QPSK_1BY2 3
/** QPSK, rate ¾ */
#define BB_MCS_QPSK_3BY4 4
/** 16-QAM, rate ½ */
#define BB_MCS_16QAM_1BY2 5
/** 16-QAM, rate ¾ */
#define BB_MCS_16QAM_3BY4 6
/** receive only MR-O-QPSK */
#define RXM_MR_OQPSK 0x0
/** receive only legacy O-QPSK */
#define RXM_LEGACY_OQPSK 0x1
/** receive both legacy & MR-O-QPSK */
#define RXM_BOTH_OQPSK 0x2
/** receive nothing */
#define RXM_DISABLE 0x3
/** Modulation Order 2-FSK */
#define FSK_MORD_2SFK (0 << FSKC0_MORD_SHIFT)
/** Modulation Order 4-FSK */
#define FSK_MORD_4SFK (1 << FSKC0_MORD_SHIFT)
/**
* FSK modulation index
* @{
*/
#define FSK_MIDX_3_BY_8 (0 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_4_BY_8 (1 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_6_BY_8 (2 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_8_BY_8 (3 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_10_BY_8 (4 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_12_BY_8 (5 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_14_BY_8 (6 << FSKC0_MIDX_SHIFT)
#define FSK_MIDX_16_BY_8 (7 << FSKC0_MIDX_SHIFT)
/** @} */
/**
* FSK modulation index scale
* @{
*/
#define FSK_MIDXS_SCALE_7_BY_8 (0 << FSKC0_MIDXS_SHIFT)
#define FSK_MIDXS_SCALE_8_BY_8 (1 << FSKC0_MIDXS_SHIFT)
#define FSK_MIDXS_SCALE_9_BY_8 (2 << FSKC0_MIDXS_SHIFT)
#define FSK_MIDXS_SCALE_10_BY_8 (3 << FSKC0_MIDXS_SHIFT)
/** @} */
/**
* FSK bandwidth time product
* @{
*/
#define FSK_BT_05 (0 << FSKC0_BT_SHIFT)
#define FSK_BT_10 (1 << FSKC0_BT_SHIFT)
#define FSK_BT_15 (2 << FSKC0_BT_SHIFT)
#define FSK_BT_20 (3 << FSKC0_BT_SHIFT)
/** @} */
/**
* FSK symbol rate (kHz)
* @{
*/
#define FSK_SRATE_50K 0x0
#define FSK_SRATE_100K 0x1
#define FSK_SRATE_150K 0x2
#define FSK_SRATE_200K 0x3
#define FSK_SRATE_300K 0x4
#define FSK_SRATE_400K 0x5
/** @} */
/**
* FSK channel spacing (kHz)
* @{
*/
#define FSK_CHANNEL_SPACING_200K 0x0
#define FSK_CHANNEL_SPACING_400K 0x1
/** @} */
/** Lower values increase the SFD detector sensitivity.
Higher values increase the SFD selectivity.
The default value 8 is recommended for simultaneous sensing
of the SFD pairs according to IEEE 802.15.4g. */
#define FSKC3_SFDT(n) (((n) << FSKC3_SFDT_SHIFT) & FSKC3_SFDT_MASK)
/** Lower values increase the preamble detector sensitivity. */
#define FSKC3_PDT(n) (((n) << FSKC3_PDT_SHIFT) & FSKC3_PDT_MASK)
/** @} */
typedef struct
{
} at86rf215_bb_phy_control_st;
void at86rf215_bb_set_phy_control (at86rf215_st *dev, at86rf215_rf_channel_en ch, at86rf215_bb_phy_control_st* pc);
void at86rf215_bb_get_phy_control (at86rf215_st *dev, at86rf215_rf_channel_en ch, at86rf215_bb_phy_control_st* pc);
#ifdef __cplusplus
}
#endif
#endif // __AT86RF215_BASEBAND_H__

Wyświetl plik

@ -1,165 +0,0 @@
#ifndef __AT86RF215_COMMON_H__
#define __AT86RF215_COMMON_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "io_utils/io_utils.h"
#include "io_utils/io_utils_spi.h"
#include "at86rf215_regs.h"
#pragma pack(1)
typedef enum
{
at86rf215_rf_channel_900mhz = 0,
at86rf215_rf_channel_2400mhz = 1,
} at86rf215_rf_channel_en;
typedef struct
{
uint8_t wake_up_por:1;
uint8_t trx_ready:1;
uint8_t energy_detection_complete:1;
uint8_t battery_low:1;
uint8_t trx_error:1;
uint8_t IQ_if_sync_fail:1;
uint8_t res :2;
} at86rf215_radio_irq_st;
typedef struct
{
uint8_t frame_rx_started:1;
uint8_t frame_rx_complete:1;
uint8_t frame_rx_address_match:1;
uint8_t frame_rx_match_extended:1;
uint8_t frame_tx_complete:1;
uint8_t agc_hold:1;
uint8_t agc_release :1;
uint8_t frame_buffer_level :1;
} at86rf215_baseband_irq_st;
typedef struct
{
at86rf215_radio_irq_st radio09;
at86rf215_radio_irq_st radio24;
at86rf215_baseband_irq_st bb0;
at86rf215_baseband_irq_st bb1;
} at86rf215_irq_st;
#pragma pack()
typedef enum
{
at86rf215_iq_drive_current_1ma = 0,
at86rf215_iq_drive_current_2ma = 1,
at86rf215_iq_drive_current_3ma = 2,
at86rf215_iq_drive_current_4ma = 3,
} at86rf215_iq_drive_current_en;
typedef enum
{
at86rf215_iq_common_mode_v_150mv = 0,
at86rf215_iq_common_mode_v_200mv = 1,
at86rf215_iq_common_mode_v_250mv = 2,
at86rf215_iq_common_mode_v_300mv = 3,
at86rf215_iq_common_mode_v_ieee1596_1v2 = 4,
} at86rf215_iq_common_mode_v_en;
typedef enum
{
at86rf215_baseband_mode = 0,
at86rf215_iq_if_mode = 1,
} at86rf215_baseband_iq_mode_en;
typedef enum
{
at86rf215_iq_clock_data_skew_1_906ns = 0,
at86rf215_iq_clock_data_skew_2_906ns = 1,
at86rf215_iq_clock_data_skew_3_906ns = 2,
at86rf215_iq_clock_data_skew_4_906ns = 3,
} at86rf215_iq_clock_data_skew_en;
typedef struct
{
uint8_t loopback_enable;
at86rf215_iq_drive_current_en drv_strength;
at86rf215_iq_common_mode_v_en common_mode_voltage;
uint8_t tx_control_with_iq_if;
at86rf215_baseband_iq_mode_en radio09_mode;
at86rf215_baseband_iq_mode_en radio24_mode;
at86rf215_iq_clock_data_skew_en clock_skew;
// status
uint8_t synchronization_failed;
uint8_t in_failsafe_mode;
uint8_t synchronized_incoming_iq;
} at86rf215_iq_interface_config_st;
typedef struct
{
int low_ch_i;
int low_ch_q;
int hi_ch_i;
int hi_ch_q;
} at86rf215_cal_results_st;
typedef struct
{
pthread_mutex_t ready_mutex;
pthread_cond_t ready_cond;
int ready;
} event_st;
typedef struct
{
event_st lo_trx_ready_event;
event_st lo_energy_measure_event;
event_st hi_trx_ready_event;
event_st hi_energy_measure_event;
} at86rf215_events_st;
typedef struct
{
// pinout
int reset_pin;
int irq_pin;
int cs_pin;
// spi device
int spi_dev;
int spi_channel;
// internal controls
io_utils_spi_st* io_spi;
int io_spi_handle;
int initialized;
at86rf215_cal_results_st cal;
bool override_cal;
at86rf215_events_st events;
int num_interrupts;
} at86rf215_st;
int at86rf215_write_buffer(at86rf215_st* dev, uint16_t addr, uint8_t *buffer, uint8_t size );
int at86rf215_read_buffer(at86rf215_st* dev, uint16_t addr, uint8_t *buffer, uint8_t size);
int at86rf215_write_byte(at86rf215_st* dev, uint16_t addr, uint8_t val );
int at86rf215_read_byte(at86rf215_st* dev, uint16_t addr);
void at86rf215_interrupt_handler (int event, int level, uint32_t tick, void *data);
int at86rf215_write_fifo(at86rf215_st* dev, uint8_t *buffer, uint8_t size );
int at86rf215_read_fifo(at86rf215_st* dev, uint8_t *buffer, uint8_t size );
void at86rf215_get_irqs(at86rf215_st* dev, at86rf215_irq_st* irq, int verbose);
#ifdef __cplusplus
}
#endif
#endif // __AT86RF215_COMMON_H__

Wyświetl plik

@ -1,157 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "AT86RF215_Events"
#include <stdio.h>
#include "zf_log/zf_log.h"
#include "at86rf215_common.h"
#include <pthread.h>
void event_node_init(event_st* ev)
{
pthread_cond_init(&ev->ready_cond, NULL);
pthread_mutex_init(&ev->ready_mutex, NULL);
}
void event_node_close(event_st* ev)
{
pthread_cond_destroy(&ev->ready_cond);
pthread_mutex_destroy(&ev->ready_mutex);
}
void event_node_wait_ready(event_st* ev)
{
pthread_mutex_lock(&ev->ready_mutex);
while (!ev->ready)
{
pthread_cond_wait(&ev->ready_cond, &ev->ready_mutex);
}
ev->ready = 0;
pthread_mutex_unlock(&ev->ready_mutex);
}
void event_node_signal_ready(event_st* ev, int ready)
{
pthread_mutex_lock(&ev->ready_mutex);
ev->ready = ready;
pthread_cond_signal(&ev->ready_cond);
pthread_mutex_unlock(&ev->ready_mutex);
}
//===================================================================
static void at86rf215_radio_event_handler (at86rf215_st* dev,
at86rf215_rf_channel_en ch,
at86rf215_radio_irq_st *events)
{
char channel_st[3];
if (ch == at86rf215_rf_channel_900mhz) strcpy(channel_st, "09");
else strcpy(channel_st, "24");
if (events->wake_up_por)
{
ZF_LOGD("INT @ RADIO%s: Woke up", channel_st);
}
if (events->trx_ready)
{
ZF_LOGD("INT @ RADIO%s: Transceiver ready", channel_st);
if (ch == at86rf215_rf_channel_900mhz) event_node_signal_ready(&dev->events.lo_trx_ready_event, 1);
else if (ch == at86rf215_rf_channel_2400mhz) event_node_signal_ready(&dev->events.hi_trx_ready_event, 1);
}
if (events->energy_detection_complete)
{
ZF_LOGD("INT @ RADIO%s: Energy detection complete", channel_st);
if (ch == at86rf215_rf_channel_900mhz) event_node_signal_ready(&dev->events.lo_energy_measure_event, 1);
else if (ch == at86rf215_rf_channel_2400mhz) event_node_signal_ready(&dev->events.hi_energy_measure_event, 1);
}
if (events->battery_low)
{
ZF_LOGD("INT @ RADIO%s: Battery low", channel_st);
}
if (events->trx_error)
{
ZF_LOGD("INT @ RADIO%s: Transceiver error", channel_st);
}
if (events->IQ_if_sync_fail)
{
ZF_LOGD("INT @ RADIO%s: I/Q interface sync failed", channel_st);
}
}
//===================================================================
static void at86rf215_baseband_event_handler (at86rf215_st* dev,
at86rf215_rf_channel_en ch,
at86rf215_baseband_irq_st *events)
{
char channel_st[3];
if (ch == at86rf215_rf_channel_900mhz) strcpy(channel_st, "09");
else strcpy(channel_st, "24");
if (events->frame_rx_started)
{
ZF_LOGD("INT @ BB%s: Frame reception started", channel_st);
}
if (events->frame_rx_complete)
{
ZF_LOGD("INT @ BB%s: Frame reception complete", channel_st);
}
if (events->frame_rx_address_match)
{
ZF_LOGD("INT @ BB%s: Frame address matched", channel_st);
}
if (events->frame_rx_match_extended)
{
ZF_LOGD("INT @ BB%s: Frame extended address matched", channel_st);
}
if (events->frame_tx_complete)
{
ZF_LOGD("INT @ BB%s: Frame transmission complete", channel_st);
}
if (events->agc_hold)
{
ZF_LOGD("INT @ BB%s: AGC hold", channel_st);
}
if (events->agc_release)
{
ZF_LOGD("INT @ BB%s: AGC released", channel_st);
}
if (events->frame_buffer_level)
{
ZF_LOGD("INT @ BB%s: Frame buffer level", channel_st);
}
}
//===================================================================
void at86rf215_interrupt_handler (int event, int level, uint32_t tick, void *data)
{
int i;
at86rf215_st* dev = (at86rf215_st*)data;
at86rf215_irq_st irq = {0};
if (level == 0) return;
// first read the irqs
at86rf215_get_irqs(dev, &irq, 0);
uint8_t *tmp = (uint8_t *)&irq;
dev->num_interrupts ++;
if (tmp[0] != 0) at86rf215_radio_event_handler (dev, at86rf215_rf_channel_900mhz, &irq.radio09);
if (tmp[1] != 0) at86rf215_radio_event_handler (dev, at86rf215_rf_channel_2400mhz, &irq.radio24);
if (tmp[2] != 0) at86rf215_baseband_event_handler (dev, at86rf215_rf_channel_900mhz, &irq.bb0);
if (tmp[3] != 0) at86rf215_baseband_event_handler (dev, at86rf215_rf_channel_2400mhz, &irq.bb1);
}

Wyświetl plik

@ -1,705 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "AT86RF215_Radio"
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "zf_log/zf_log.h"
#include "io_utils/io_utils.h"
#include "io_utils/io_utils_spi.h"
#include "at86rf215_radio.h"
#include "at86rf215_regs.h"
static const struct at86rf215_radio_regs RF09_regs = {
.RG_IRQS = 0x00,
.RG_IRQM = 0x100,
.RG_AUXS = 0x101,
.RG_STATE = 0x102,
.RG_CMD = 0x103,
.RG_CS = 0x104,
.RG_CCF0L = 0x105,
.RG_CCF0H = 0x106,
.RG_CNL = 0x107,
.RG_CNM = 0x108,
.RG_RXBWC = 0x109,
.RG_RXDFE = 0x10A,
.RG_AGCC = 0x10B,
.RG_AGCS = 0x10C,
.RG_RSSI = 0x10D,
.RG_EDC = 0x10E,
.RG_EDD = 0x10F,
.RG_EDV = 0x110,
.RG_RNDV = 0x111,
.RG_TXCUTC = 0x112,
.RG_TXDFE = 0x113,
.RG_PAC = 0x114,
.RG_PADFE = 0x116,
.RG_PLL = 0x121,
.RG_PLLCF = 0x122,
.RG_TXCI = 0x125,
.RG_TXCQ = 0x126,
.RG_TXDACI = 0x127,
.RG_TXDACQ = 0x128,
};
static const struct at86rf215_radio_regs RF24_regs = {
.RG_IRQS = 0x01,
.RG_IRQM = 0x200,
.RG_AUXS = 0x201,
.RG_STATE = 0x202,
.RG_CMD = 0x203,
.RG_CS = 0x204,
.RG_CCF0L = 0x205,
.RG_CCF0H = 0x206,
.RG_CNL = 0x207,
.RG_CNM = 0x208,
.RG_RXBWC = 0x209,
.RG_RXDFE = 0x20A,
.RG_AGCC = 0x20B,
.RG_AGCS = 0x20C,
.RG_RSSI = 0x20D,
.RG_EDC = 0x20E,
.RG_EDD = 0x20F,
.RG_EDV = 0x210,
.RG_RNDV = 0x211,
.RG_TXCUTC = 0x212,
.RG_TXDFE = 0x213,
.RG_PAC = 0x214,
.RG_PADFE = 0x216,
.RG_PLL = 0x221,
.RG_PLLCF = 0x222,
.RG_TXCI = 0x225,
.RG_TXCQ = 0x226,
.RG_TXDACI = 0x227,
.RG_TXDACQ = 0x228,
};
#define AT86RF215_REG_ADDR(c,r) \
(((c)==at86rf215_rf_channel_900mhz)?(RF09_regs.RG_##r):(RF24_regs.RG_##r))
//==================================================================================
void at86rf215_radio_setup_interrupt_mask(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_irq_st* mask)
{
uint16_t reg_address = AT86RF215_REG_ADDR(ch, IRQM);
at86rf215_write_byte(dev, reg_address, *((uint8_t*)mask));
}
//==================================================================================
void at86rf215_radio_setup_external_settings(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_external_ctrl_st* cfg)
{
// "RG_AUXS" RFn_AUXS – Transceiver Auxiliary Settings
uint16_t reg_address_aux = AT86RF215_REG_ADDR(ch, AUXS);
uint16_t reg_address_pad = AT86RF215_REG_ADDR(ch, PADFE);
uint8_t aux = 0;
aux |= (cfg->ext_lna_bypass_available&0x1) << 7;
aux |= (cfg->agc_backoff&0x3) << 5;
aux |= (cfg->analog_voltage_external&0x1) << 4;
aux |= (cfg->analog_voltage_enable_in_off&0x1) << 3;
aux |= (cfg->int_power_amplifier_voltage&0x3) << 0;
at86rf215_write_byte(dev, reg_address_aux, aux);
uint8_t pad = (cfg->fe_pad_configuration&0x3) << 6;
at86rf215_write_byte(dev, reg_address_pad, pad);
}
//==================================================================================
void at86rf215_radio_get_external_settings(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_external_ctrl_st* cfg)
{
uint16_t reg_address_aux = AT86RF215_REG_ADDR(ch, AUXS);
uint16_t reg_address_pad = AT86RF215_REG_ADDR(ch, PADFE);
uint8_t aux = at86rf215_read_byte(dev, reg_address_aux);
uint8_t pad = at86rf215_read_byte(dev, reg_address_pad);
cfg->fe_pad_configuration = pad>>6;
cfg->ext_lna_bypass_available = (aux>>7) & 0x1;
cfg->agc_backoff = (aux>>5) & 0x3;
cfg->analog_voltage_external = (aux>>4) & 0x1;
cfg->analog_voltage_enable_in_off = (aux>>3) & 0x1;
cfg->analog_voltage_status = (aux>>2) & 0x1;
cfg->int_power_amplifier_voltage = (aux>>0) & 0x2;
}
//==================================================================================
at86rf215_radio_state_cmd_en at86rf215_radio_get_state(at86rf215_st* dev, at86rf215_rf_channel_en ch)
{
// "RG_STATE" RFn_STATE – Transceiver State
uint16_t reg_address = AT86RF215_REG_ADDR(ch, STATE);
uint8_t state = at86rf215_read_byte(dev, reg_address);
return state & 0x7;
}
//==================================================================================
void at86rf215_radio_set_state(at86rf215_st* dev, at86rf215_rf_channel_en ch, at86rf215_radio_state_cmd_en cmd)
{
// "RG_CMD" RFn_CMD – Transceiver Command
uint16_t reg_address = AT86RF215_REG_ADDR(ch, CMD);
at86rf215_write_byte(dev, reg_address, cmd & 0x7);
/*Errata #6: State Machine Command RFn_CMD=TRXOFF may not be succeeded
Description: If the current state is different from SLEEP, the execution of the command TRXOFF may fail.
Software workaround: Check state by reading register RFn_STATE Repeat the command RFn_CMD=TRXOFF
if the target state was not reached.
*/
if (cmd == at86rf215_radio_state_cmd_trx_off)
{
int retries = 5;
while (at86rf215_radio_get_state(dev, ch) != cmd && retries--)
{
io_utils_usleep(100);
at86rf215_write_byte(dev, reg_address, cmd & 0x7);
}
}
if (cmd == at86rf215_radio_state_cmd_tx_prep || cmd == at86rf215_radio_state_cmd_tx || cmd == at86rf215_radio_state_cmd_rx)
{
//if (ch == at86rf215_rf_channel_900mhz) event_node_wait_ready(&dev->events.lo_trx_ready_event);
//else if (ch == at86rf215_rf_channel_2400mhz) event_node_wait_ready(&dev->events.hi_trx_ready_event);
io_utils_usleep(1000);
if (dev->override_cal)
{
int i = ch == at86rf215_rf_channel_900mhz ? dev->cal.low_ch_i : dev->cal.hi_ch_i;
int q = ch == at86rf215_rf_channel_900mhz ? dev->cal.low_ch_q : dev->cal.hi_ch_q;
at86rf215_radio_set_tx_iq_calibration(dev, ch, i, q);
}
}
}
static double _fine_freq_starts[] = {0, 377e6, 754e6, 2366e6, 2550e6};
static double _fine_freq_pll_src[] = {0, 6.5e6, 13e6, 26e6};
//static int _fine_freq_ccf_min[] = {0, 126030, 126030, 85700};
//static int _fine_freq_ccf_max[] = {0, 1340967, 1340967, 296172};
//==================================================================================
int at86rf215_radio_get_good_channel(double wanted_frequency_hz, at86rf215_radio_channel_mode_en *mode,
at86rf215_rf_channel_en *ch)
{
if ( wanted_frequency_hz >= _fine_freq_starts[at86rf215_radio_channel_mode_fine_high]
&& wanted_frequency_hz < _fine_freq_starts[at86rf215_radio_channel_mode_fine_high+1])
{
*ch = at86rf215_rf_channel_2400mhz;
*mode = at86rf215_radio_channel_mode_fine_high;
}
else if ( wanted_frequency_hz >= _fine_freq_starts[at86rf215_radio_channel_mode_fine_mid]
&& wanted_frequency_hz < _fine_freq_starts[at86rf215_radio_channel_mode_fine_high] )
{
*ch = at86rf215_rf_channel_900mhz;
*mode = at86rf215_radio_channel_mode_fine_mid;
}
else if ( wanted_frequency_hz >= _fine_freq_starts[at86rf215_radio_channel_mode_fine_low]
&& wanted_frequency_hz < _fine_freq_starts[at86rf215_radio_channel_mode_fine_mid] )
{
*ch = at86rf215_rf_channel_900mhz;
*mode = at86rf215_radio_channel_mode_fine_low;
}
else
{
ZF_LOGE("the requested frequency %.1f Hz not supported", wanted_frequency_hz);
return -1;
}
return 0;
}
//==================================================================================
double at86rf215_radio_get_frequency( /*IN*/ at86rf215_radio_channel_mode_en mode,
/*IN*/ int channel_spacing_25khz_res,
/*IN*/ double wanted_frequency_hz,
/*OUT*/ int *center_freq_25khz_res,
/*OUT*/ int *channel_number)
{
// "RG_CS" RFn_CS – Channel Spacing
/*
The register configures the channel spacing with a resolution of 25kHz. The register CNM must be written to take over
the CS value. The CNM register must always be written last.
Example: A value of 0x08 needs to be set (8x25kHz) for a channel spacing of 200kHz.
*/
// "RG_CCF0L, RG_CCF0H" RFn_CCF0(L/H) – Channel Center Frequency F0 Low/High Byte
/*
The register configures the base value of the channel center frequency F0 (low / high byte) with a resolution of 25kHz.
The register CNM must be written to latch the CCFOL/H value. The CNM register must always be written last.
VALUES: The reset value (0xf8) of the channel register results in 902.2MHz for the sub-1GHz transceiver (RF09)
and 2402.2MHz for the 2.4GHz transceiver (RF24): CCF0=0x8cf8=36088; CS=200KHz, CN=0.
HOW:
F_rf09 = CCF0*25khz
F_rf24 = 1500000 + CCF0 * 25
F_rf09(default) = 36088 * 25 = 902,200 kHz
F_rf24(default) = 1500000 + 36088 * 25 = 2,402,200 kHz
*/
// "RG_CNL" RFn_CNL – Channel Number Low Byte
// "RG_CNM" RFn_CNM – Channel Mode and Channel Number High Bit
// in total the CNL/M contains 9 bits of channel and the LATCH (Mode)
/*
CNL - The register contains the transceiver channel number low byte CN[7:0]. The register CNM must be written to latch the
CNL value. The CNM register must always be written last.
CNM - The register configures the channel mode and channel number bit 9 CN[8]. A write operation to this register applies the
channel register CS, CCFOL, CCFOH and CNL values.
0x0 IEEE compliant channel scheme; f=(CCF0+CN*CS)*25kHz+f_offset ; (f_offset = 0Hz/1.5GHz)
0x1 Fine resolution (389.5-510.0)MHz with 99.182Hz channel stepping
0x2 Fine resolution (779-1020)MHz with 198.364Hz channel stepping
0x3 Fine resolution (2400-2483.5)MHz with 396.728Hz channel stepping
*/
if (mode == at86rf215_radio_channel_mode_ieee)
{
float f_offset = (wanted_frequency_hz>1500e6)?1500e6:0.0f;
*center_freq_25khz_res = (int)((wanted_frequency_hz - f_offset) / 25e3);
*channel_number = 0;
return f_offset + (*center_freq_25khz_res)*25e3;
}
int nchannel = (int)((wanted_frequency_hz - _fine_freq_starts[mode]) * ((float)(1<<16)) / _fine_freq_pll_src[mode]);
float actual_freq = (nchannel*_fine_freq_pll_src[mode]) / ((float)(1<<16)) + _fine_freq_starts[mode];
*center_freq_25khz_res = (nchannel >> 8) & 0xFFFF;
*channel_number = (nchannel >> 0) & 0xFF;
return actual_freq;
}
//==================================================================================
void at86rf215_radio_setup_channel(at86rf215_st* dev, at86rf215_rf_channel_en ch,
int channel_spacing_25khz_res,
int center_freq_25khz_res,
int channel_number,
at86rf215_radio_channel_mode_en mode)
{
uint16_t reg_address_spacing = AT86RF215_REG_ADDR(ch, CS);
uint8_t buf[5] = {0};
buf[0] = channel_spacing_25khz_res;
buf[1] = /*LOW*/ center_freq_25khz_res & 0xFF;
buf[2] = /*HIGH*/ (center_freq_25khz_res >> 8) & 0xFF;
buf[3] = /*LOW*/ channel_number & 0xFF;
buf[4] = /*HIGH + MODE*/ ((channel_number>>8)&0x01) | ((mode & 0x3)<<6);
at86rf215_write_buffer(dev, reg_address_spacing, buf, 5);
}
//==================================================================================
void at86rf215_radio_set_rx_bandwidth_sampling(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_set_rx_bw_samp_st* cfg)
{
// "RG_RXBWC" RFn_RXBWC – Receiver Filter Bandwidth Control
/*
The register configures the receiver filter settings.
- Bit 5 RXBWC.IFI: IF Inversion
A value of one configures the receiver to implement the inverted-sign IF frequency.
Use default setting for normal operation.
- Bit 4 RXBWC.IFS: IF Shift
A value of one configures the receiver to shift the IF frequency by factor of 1.25.
This is useful to place the image frequency according to channel scheme.
- Bit 3:0 RXBWC.BW: Receiver Bandwidth
The sub-register controls the receiver filter bandwidth settings.
*/
// "RG_RXDFE" RFn_RXDFE – Receiver Digital Frontend
/*
The register configures the receiver digital frontend
Bit 7:5 RXDFE.RCUT: RX filter relative cut-off frequency
Bit 3:0 RXDFE.SR: RX Sample Rate
*/
uint16_t reg_address_bw = AT86RF215_REG_ADDR(ch, RXBWC);
uint8_t buf[2] = {0};
buf[0] |= (cfg->inverter_sign_if & 0x1)<<5;
buf[0] |= (cfg->shift_if_freq & 0x1)<<4;
buf[0] |= (cfg->bw & 0xF);
buf[1] |= (cfg->fcut & 0x7) << 5;
buf[1] |= (cfg->fs & 0xF);
at86rf215_write_buffer(dev, reg_address_bw, buf, 2);
}
//==================================================================================
void at86rf215_radio_get_rx_bandwidth_sampling(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_set_rx_bw_samp_st* cfg)
{
uint16_t reg_address_bw = AT86RF215_REG_ADDR(ch, RXBWC);
uint8_t buf[2] = {0};
at86rf215_read_buffer(dev, reg_address_bw, buf, 2);
cfg->inverter_sign_if = (buf[0]>>5) & 0x1;
cfg->shift_if_freq = (buf[0]>>4) & 0x1;
cfg->bw = (buf[0]>>0) & 0xF;
cfg->fcut = (buf[1]>>5) & 0x7;
cfg->fs = (buf[1]>>0) & 0xF;
}
//==================================================================================
void at86rf215_radio_setup_agc(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_agc_ctrl_st *agc_ctrl)
{
// "RG_AGCC, RG_AGCS" RFn_AGCC – Receiver AGC Control 0 / RFn_AGCS – Receiver AGCG
/*
RFn_AGCC Receiver AGC Control 0:
The register controls the transceiver automatic gain control (AGC).
Bit 6 AGCC.AGCI: AGC Input (0 - filterred, 1 - unfiltered, faster operation)
Bit 5:4 AGCC.AVGS: AGC Average Time in Number of Samples
0x0 8 samples
0x1 16 samples
0x2 32 samples
0x3 64 samples
Bit 3 AGCC.RST: AGC Reset - resets the AGC and sets the maximum receiver gain.
Bit 2 AGCC.FRZS: AGC Freeze Status - A value of one indicates that the AGC is on hold.
Bit 1 AGCC.FRZC: AGC Freeze Control - A value of one forces the AGC to freeze to its current value.
Bit 0 AGCC.EN: AGC Enable - a value of zero allows a manual setting of the RX gain control by sub-register AGCS.GCW
RFn_AGCS Receiver AGCG:
The register controls the AGC and the receiver gain.
Bit 7:5 AGCS.TGT: AGC Target Level - sets the AGC target level relative to ADC full scale.
0x0 Target=-21dB
0x1 Target=-24dB
0x2 Target=-27dB
0x3 Target=-30dB
0x4 Target=-33dB
0x5 Target=-36dB
0x6 Target=-39dB
0x7 Target=-42dB
Bit 4:0 AGCS.GCW: RX Gain Control Word
If AGCC_EN is set to 1, a read of bit AGCS.GCW indicates the current receiver gain setting. If AGCC_EN is set to 0, a
write access to GCW manually sets the receiver gain. An integer value of 23 indicates the maximum receiver gain; each
integer step changes the gain by 3dB.
*/
uint16_t reg_address_agc = AT86RF215_REG_ADDR(ch, AGCC);
uint8_t buf[2] = {0};
buf[0] |= (agc_ctrl->agc_measure_source_not_filtered & 0x1)<<6;
buf[0] |= (agc_ctrl->avg & 0x3)<<4;
buf[0] |= (agc_ctrl->reset_cmd & 0x1) << 3;
buf[0] |= (agc_ctrl->freeze_cmd & 0x1) << 1;
buf[0] |= (agc_ctrl->enable_cmd & 0x1);
buf[1] |= (agc_ctrl->att & 0x7) << 5;
buf[1] |= (agc_ctrl->gain_control_word & 0x1F);
at86rf215_write_buffer(dev, reg_address_agc, buf, 2);
}
//==================================================================================
void at86rf215_radio_get_agc(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_agc_ctrl_st *agc_ctrl)
{
uint16_t reg_address_agc = AT86RF215_REG_ADDR(ch, AGCC);
uint8_t buf[2] = {0};
at86rf215_read_buffer(dev, reg_address_agc, buf, 2);
agc_ctrl->agc_measure_source_not_filtered = (buf[0] >> 6);
agc_ctrl->avg = (buf[0] >> 4) & 0x1;
agc_ctrl->reset_cmd = (buf[0] >> 3) & 0x3;
agc_ctrl->freeze_status = (buf[0] >> 2) & 0x1;
agc_ctrl->freeze_cmd = (buf[0] >> 1) & 0x1;
agc_ctrl->enable_cmd = (buf[0] >> 0) & 0x1;
agc_ctrl->att = (buf[1] >> 5) & 0x7;
agc_ctrl->gain_control_word = (buf[1] >> 0) & 0x1F;
}
//==================================================================================
float at86rf215_radio_get_rssi_dbm(at86rf215_st* dev, at86rf215_rf_channel_en ch)
{
// "RG_RSSI" RFn_RSSI – Received Signal Strength Indicator
/*
Bit 7:0 RSSI.RSSI: Received Signal Strength Indicator
The value reflects the received signal power in dBm. A value of 127 indicates that the RSSI value is invalid. The register value presents a signed
integer value (value range -127...+4) using twos complement representation.
*/
uint16_t reg_address = AT86RF215_REG_ADDR(ch, RSSI);
uint8_t v = at86rf215_read_byte(dev, reg_address);
int8_t *sv = (int8_t *)&v;
return (float)(*sv);
}
//==================================================================================
void at86rf215_radio_setup_energy_detection(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_energy_detection_st* ed)
{
/*
"RG_EDC" "RG_EDD" "RG_EDV"
RFn_EDC Energy Detection Configuration
Bit 1:0 EDC.EDM: Energy Detection Mode (at86rf215_radio_energy_detection_mode_en)
RFn_EDD Receiver Energy Detection Averaging Duration
Bit 7:2 EDD.DF: Receiver energy detection duration factor - T[μs]=DF*DTB
Bit 1:0 EDD.DTB: Receiver energy detection average duration time basis (RSSI averaging basis)
0x0 2μs
0x1 8μs
0x2 32μs
0x3 128μs
*/
uint16_t reg_address_edc = AT86RF215_REG_ADDR(ch, EDC);
uint8_t buf[2] = {0};
buf[0] |= (ed->mode & 0x3)<<0;
// find the closest usec number
int df = ed->average_duration_us / 2;
int dtb = 0;
if (df > 63)
{
df = ed->average_duration_us / 8;
dtb = 1;
if (df > 63)
{
df = ed->average_duration_us / 32;
dtb = 2;
if (df > 63)
{
df = ed->average_duration_us / 128;
dtb = 3;
if (df > 63)
{
df = 63;
}
}
}
}
buf[1] |= (df & 0x3F) << 2;
buf[1] |= (dtb & 0x3);
at86rf215_write_buffer(dev, reg_address_edc, buf, 2);
}
//==================================================================================
void at86rf215_radio_get_energy_detection(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_energy_detection_st* ed)
{
uint16_t reg_address_edc = AT86RF215_REG_ADDR(ch, EDC);
uint8_t buf[3] = {0};
at86rf215_read_buffer(dev, reg_address_edc, buf, 3);
ed->mode = (buf[0]) & 0x3;
buf[0] |= (ed->mode & 0x3)<<0;
float dtb = 0.0f;
switch (buf[1] & 0x3)
{
case 0: dtb = 2.0f; break;
case 1: dtb = 8.0f; break;
case 2: dtb = 32.0f; break;
case 3: dtb = 64.0f; break;
default: dtb = 2.0f; break;
}
float df = (buf[1] >> 2) & 0x3;
ed->average_duration_us = df * dtb;
ed->energy_detection_value = (float)(*(int8_t*)(&buf[2]));
}
//==================================================================================
uint8_t at86rf215_radio_get_random_value(at86rf215_st* dev, at86rf215_rf_channel_en ch)
{
// "RG_RNDV" RFn_RNDV – Random Value - contains 8bit random value
uint16_t reg_address = AT86RF215_REG_ADDR(ch, RNDV);
return at86rf215_read_byte(dev, reg_address);
}
//==================================================================================
void at86rf215_radio_setup_tx_ctrl(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_tx_ctrl_st* cfg)
{
/*
RFn_TXCUTC Transmitter Filter Cutoff Control and PA Ramp Time
Bit 7:6 TXCUTC.PARAMP: Power Amplifier Ramp Time
RF_PARAMP4U 0x0 tpa_ramp = 4μs
RF_PARAMP8U 0x1 tpa_ramp = 8μs
RF_PARAMP16U 0x2 tpa_ramp = 16μs
RF_PARAMP32U 0x3 tpa_ramp = 32μs
Bit 3:0 TXCUTC.LPFCUT: Transmitter cut-off frequency
RF_FLC80KHZ 0x0 fLPFCUT = 80kHz
RF_FLC100KHZ 0x1 fLPFCUT = 100kHz
RF_FLC125KHZ 0x2 fLPFCUT = 125kHz
RF_FLC160KHZ 0x3 fLPFCUT = 160kHz
RF_FLC200KHZ 0x4 fLPFCUT = 200kHz
RF_FLC250KHZ 0x5 fLPFCUT = 250kHz
RF_FLC315KHZ 0x6 fLPFCUT = 315kHz
RF_FLC400KHZ 0x7 fLPFCUT = 400kHz
RF_FLC500KHZ 0x8 fLPFCUT = 500kHz
RF_FLC625KHZ 0x9 fLPFCUT = 625kHz
RF_FLC800KHZ 0xA fLPFCUT = 800kHz
RF_FLC1000KHZ 0xB fLPFCUT = 1000kHz
*/
/*
RFn_TXDFE Transmitter TX Digital Frontend
Bit 7:5 TXDFE.RCUT: TX filter relative to the cut-off frequency
0x0 fCUT=0.25 *fS/2
0x1 fCUT=0.375*fS/2
0x2 fCUT=0.5 *fS/2
0x3 fCUT=0.75 *fS/2
0x4 fCUT=1.00 *fS/2
Bit 4 TXDFE.DM: Direct Modulation
If enabled (1) the transmitter direct modulation is enabled - available for FSK and
OQPSK (OQPSKC0.FCHIP=0;1). Direct modulation must also be enabled at the BBCx registers (FSKDM.EN and OQPSKC0.DM).
Bit 3:0 TXDFE.SR: TX Sample Rate
0x1 fS=4000kHz
0x2 fS=2000kHz
0x3 fS=(4000/3)kHz
0x4 fS=1000kHz
0x5 fS=800kHz
0x6 fS=(2000/3)kHz
0x8 fS=500kHz
0xA fS=400kHz
*/
/*
RFn_PAC Transmitter Power Amplifier Control
Bit 6:5 PAC.PACUR: Power Amplifier Current Control - PACUR configures the power amplifier DC current (useful for low power settings).
0x0 Power amplifier current reduction by about 22mA (3dB reduction of max. small signal gain)
0x1 Power amplifier current reduction by about 18mA (2dB reduction of max. small signal gain)
0x2 Power amplifier current reduction by about 11mA (1dB reduction of max. small signal gain)
0x3 No power amplifier current reduction (max. transmit small signal gain)
Bit 4:0 PAC.TXPWR: Transmitter Output Power
Maximum output power is TXPWR=31, minimum output power is TXPWR=0. The output power can be set by about 1dB step resolution.
*/
uint16_t reg_address_txcut = AT86RF215_REG_ADDR(ch, TXCUTC);
uint8_t buf[3] = {0};
buf[0] |= (cfg->pa_ramping_time & 0x3) << 6;
buf[0] |= (cfg->analog_bw & 0xF);
buf[1] |= (cfg->digital_bw & 0x7) << 5;
buf[1] |= (cfg->direct_modulation & 0x1) << 4;
buf[1] |= (cfg->fs & 0xF);
buf[2] |= (cfg->current_reduction & 0x3) << 5;
buf[2] |= (cfg->tx_power & 0x1F);
at86rf215_write_buffer(dev, reg_address_txcut, buf, 3);
}
//==================================================================================
void at86rf215_radio_get_tx_ctrl(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_tx_ctrl_st* cfg)
{
uint16_t reg_address_txcut = AT86RF215_REG_ADDR(ch, TXCUTC);
uint8_t buf[3] = {0};
at86rf215_read_buffer(dev, reg_address_txcut, buf, 3);
cfg->pa_ramping_time = (buf[0] >> 6) & 0x3;
cfg->analog_bw = (buf[0] >> 0) & 0xF;
cfg->digital_bw = (buf[1] >> 5) & 0x7;
cfg->direct_modulation = (buf[1] >> 4) & 0x1;
cfg->fs = (buf[1] >> 0) & 0xF;
cfg->current_reduction = (buf[2] >> 5) & 0x3;
cfg->tx_power = (buf[2] >> 0) & 0x1F;
}
//==================================================================================
void at86rf215_radio_setup_pll_ctrl(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_pll_ctrl_st* cfg)
{
uint16_t reg_address_pll = AT86RF215_REG_ADDR(ch, PLL);
uint8_t buf[2] = {0};
buf[0] |= (cfg->loop_bw & 0x3) << 4;
//buf[0] |= (cfg->pll_locked & 0x1) << 1; <- status
buf[1] |= (cfg->pll_center_freq & 0x3F) << 0;
at86rf215_write_buffer(dev, reg_address_pll, buf, 2);
}
//==================================================================================
void at86rf215_radio_get_pll_ctrl(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_pll_ctrl_st* cfg)
{
uint16_t reg_address_pll = AT86RF215_REG_ADDR(ch, PLL);
uint8_t buf[2] = {0};
at86rf215_read_buffer(dev, reg_address_pll, buf, 2);
cfg->loop_bw = (buf[0] >> 4) & 0x3;
cfg->pll_locked = (buf[0] >> 1) & 0x1;
cfg->pll_center_freq = (buf[1] >> 0) & 0x3F;
}
//==================================================================================
void at86rf215_radio_set_tx_iq_calibration(at86rf215_st* dev, at86rf215_rf_channel_en ch,
int cal_i, int cal_q)
{
uint16_t reg_address_cal_i = AT86RF215_REG_ADDR(ch, TXCI);
uint8_t buf[2] = {0};
buf[0] = cal_i & 0x3F;
buf[1] = cal_q & 0x3F;
at86rf215_write_buffer(dev, reg_address_cal_i, buf, 2);
// RFn_TXCI – Transmit calibration I path
// The register contains information about the TX LO leakage calibration value of the transmit I path. At the transition
// process from state TRXOFF to TX the calibration is started automatically
// RFn_TXCQ – Transmit calibration Q path
// The register contains information about the TX LO leakage calibration value of the transmit Q path. At the transition
// process from state TRXOFF to TX the calibration is started automatically.
}
//==================================================================================
void at86rf215_radio_get_tx_iq_calibration(at86rf215_st* dev, at86rf215_rf_channel_en ch,
int *cal_i, int *cal_q)
{
uint16_t reg_address_cal_i = AT86RF215_REG_ADDR(ch, TXCI);
uint16_t reg_address_cal_q = AT86RF215_REG_ADDR(ch, TXCQ);
uint8_t buf[2] = {0};
at86rf215_read_buffer(dev, reg_address_cal_i, buf, 2);
*cal_i = buf[0] & 0x3F;
*cal_q = buf[1] & 0x3F;
}
//==================================================================================
void at86rf215_radio_set_tx_dac_input_iq(at86rf215_st* dev, at86rf215_rf_channel_en ch,
int enable_dac_i_dc, int dac_i_val,
int enable_dac_q_dc, int dac_q_val)
{
uint16_t reg_address_dac_i = AT86RF215_REG_ADDR(ch, TXDACI);
uint8_t buf[2] = {0};
buf[0] = ((enable_dac_i_dc & 0x1)<<7) | (dac_i_val & 0x7F);
buf[1] = ((enable_dac_q_dc & 0x1)<<7) | (dac_q_val & 0x7F);
at86rf215_write_buffer(dev, reg_address_dac_i, buf, 2);
// RFn_TXDACI – In-phase input value for TXDAC - Input I value can be applied at TXDAC (DC measurement)
// Bit 7 – TXDACI.ENTXDACID: Enable input to TXDAC
// Bit 6:0 – TXDACI.TXDACID: Input to TXDAC data
// RFn_TXDACQ – Quadrature-phase input value for TXDAC - Input Q value can be applied at TXDAC (DC measurement)
// Bit 7 – TXDACQ.ENTXDACQD: Enable input to TXDAC
// Bit 6:0 – TXDACQ.TXDACQD: Input to TXDAC data
/*
PAGE 221 in datasheet!
The AT86RF215 comprises a DAC (digital to analog converter) value overwrite functionality. Each transceiver contains
two transmitter DACs (for the in-phase and quadrature-phase signal) in order to transmit IQ signals. Both DAC values
can be overwritten separately by register settings. This feature is useful to transmit an LO carrier which is necessary for
certain certifications.
*/
}
//==================================================================================
void at86rf215_radio_get_tx_dac_input_iq(at86rf215_st* dev, at86rf215_rf_channel_en ch,
int *enable_dac_i_dc, int *dac_i_val,
int *enable_dac_q_dc, int *dac_q_val)
{
uint16_t reg_address_dac_i = AT86RF215_REG_ADDR(ch, TXDACI);
uint8_t buf[2] = {0};
at86rf215_read_buffer(dev, reg_address_dac_i, buf, 2);
*enable_dac_i_dc = (buf[0] >> 7) & 0x1;
*enable_dac_q_dc = (buf[1] >> 7) & 0x1;
*dac_i_val = (buf[0]) & 0x3F;
*dac_q_val = (buf[1]) & 0x3F;
}

Wyświetl plik

@ -1,374 +0,0 @@
#ifndef __AT86RF215_RADIO_H__
#define __AT86RF215_RADIO_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdint.h>
#include "at86rf215_common.h"
struct at86rf215_radio_regs
{
uint16_t RG_IRQS;
uint16_t RG_IRQM;
uint16_t RG_AUXS;
uint16_t RG_STATE;
uint16_t RG_CMD;
uint16_t RG_CS;
uint16_t RG_CCF0L;
uint16_t RG_CCF0H;
uint16_t RG_CNL;
uint16_t RG_CNM;
uint16_t RG_RXBWC;
uint16_t RG_RXDFE;
uint16_t RG_AGCC;
uint16_t RG_AGCS;
uint16_t RG_RSSI;
uint16_t RG_EDC;
uint16_t RG_EDD;
uint16_t RG_EDV;
uint16_t RG_RNDV;
uint16_t RG_TXCUTC;
uint16_t RG_TXDFE;
uint16_t RG_PAC;
uint16_t RG_PADFE;
uint16_t RG_PLL;
uint16_t RG_PLLCF;
uint16_t RG_TXCI;
uint16_t RG_TXCQ;
uint16_t RG_TXDACI;
uint16_t RG_TXDACQ;
};
typedef enum
{
at86rf215_radio_cmd_nop = 0x0, // No operation (dummy)
at86rf215_radio_cmd_sleep = 0x1, // Go to sleep
at86rf215_radio_state_cmd_trx_off = 0x2, // Transceiver off, SPI active
at86rf215_radio_state_cmd_tx_prep = 0x3, // Transmit preparation
at86rf215_radio_state_cmd_tx = 0x4, // Transmit
at86rf215_radio_state_cmd_rx = 0x5, // Receive
at86rf215_radio_state_transition = 0x6, // State transition in progress
at86rf215_radio_state_cmd_reset = 0x7, // Transceiver is in state RESET or SLEEP
// if commanded reset, the transceiver state will
// automatically end up in state TRXOFF
} at86rf215_radio_state_cmd_en;
typedef enum
{
at86rf215_radio_channel_mode_ieee = 0x00,
// IEEE compliant channel scheme; f=(CCF0+CN*CS)*25kHz+f offset ;
// (f offset = 0Hz for sub-1GHz transceiver; f offset = 1.5GHz for 2.4GHz transceiver)
at86rf215_radio_channel_mode_fine_low = 0x01,
// Fine resolution (389.5-510.0)MHz with 99.182Hz channel stepping
at86rf215_radio_channel_mode_fine_mid = 0x02,
// Fine resolution (779-1020)MHz with 198.364Hz channel stepping
at86rf215_radio_channel_mode_fine_high = 0x03,
// Fine resolution (2400-2483.5)MHz with 396.728Hz channel stepping
} at86rf215_radio_channel_mode_en;
/** offset (in Hz) for CCF0 in 2.4 GHz mode */
#define CCF0_24G_OFFSET 1500000U
typedef enum
{
at86rf215_radio_rx_bw_BW160KHZ_IF250KHZ = 0x0, // at86rf215_radio_rx_f_cut_0_25_half_fs
at86rf215_radio_rx_bw_BW200KHZ_IF250KHZ = 0x1, // at86rf215_radio_rx_f_cut_0_25_half_fs
at86rf215_radio_rx_bw_BW250KHZ_IF250KHZ = 0x2, // at86rf215_radio_rx_f_cut_0_25_half_fs
at86rf215_radio_rx_bw_BW320KHZ_IF500KHZ = 0x3, // at86rf215_radio_rx_f_cut_0_25_half_fs
at86rf215_radio_rx_bw_BW400KHZ_IF500KHZ = 0x4, // at86rf215_radio_rx_f_cut_0_25_half_fs
at86rf215_radio_rx_bw_BW500KHZ_IF500KHZ = 0x5, // at86rf215_radio_rx_f_cut_0_25_half_fs
at86rf215_radio_rx_bw_BW630KHZ_IF1000KHZ = 0x6, // at86rf215_radio_rx_f_cut_0_375_half_fs
at86rf215_radio_rx_bw_BW800KHZ_IF1000KHZ = 0x7, // at86rf215_radio_rx_f_cut_0_5_half_fs
at86rf215_radio_rx_bw_BW1000KHZ_IF1000KHZ = 0x8, // at86rf215_radio_rx_f_cut_0_5_half_fs
at86rf215_radio_rx_bw_BW1250KHZ_IF2000KHZ = 0x9, // at86rf215_radio_rx_f_cut_0_75_half_fs
at86rf215_radio_rx_bw_BW1600KHZ_IF2000KHZ = 0xA, // at86rf215_radio_rx_f_cut_half_fs
at86rf215_radio_rx_bw_BW2000KHZ_IF2000KHZ = 0xB, // at86rf215_radio_rx_f_cut_half_fs
at86rf215_radio_rx_bw_BW2000KHZ_IFCCKHZ = 0xC, // **
at86rf215_radio_rx_bw_BW2000KHZ_IFDDHZ = 0xD, // **
at86rf215_radio_rx_bw_BW2000KHZ_IFEEKHZ = 0xE, // **
at86rf215_radio_rx_bw_BW2000KHZ_IFFFKHZ = 0xF, // **
} at86rf215_radio_rx_bw_en;
typedef enum
{
at86rf215_radio_rx_f_cut_0_25_half_fs = 0, // whan 4MSPS => 500 KHz
at86rf215_radio_rx_f_cut_0_375_half_fs = 1, // whan 4MSPS => 750 KHz
at86rf215_radio_rx_f_cut_0_5_half_fs = 2, // whan 4MSPS => 1000 KHz
at86rf215_radio_rx_f_cut_0_75_half_fs = 3, // whan 4MSPS => 1500 KHz
at86rf215_radio_rx_f_cut_half_fs = 4, // whan 4MSPS => 2000 KHz
} at86rf215_radio_f_cut_en;
typedef enum
{
at86rf215_radio_rx_sample_rate_4000khz = 0x1,
at86rf215_radio_rx_sample_rate_2000khz = 0x2,
at86rf215_radio_rx_sample_rate_1333khz = 0x3,
at86rf215_radio_rx_sample_rate_1000khz = 0x4,
at86rf215_radio_rx_sample_rate_800khz = 0x5,
at86rf215_radio_rx_sample_rate_666khz = 0x6,
at86rf215_radio_rx_sample_rate_500khz = 0x8,
at86rf215_radio_rx_sample_rate_400khz = 0xA,
} at86rf215_radio_sample_rate_en;
typedef enum
{
at86rf215_radio_agc_averaging_8 = 0,
at86rf215_radio_agc_averaging_16 = 1,
at86rf215_radio_agc_averaging_32 = 2,
at86rf215_radio_agc_averaging_64 = 3,
} at86rf215_radio_agc_averaging_en;
typedef enum
{
at86rf215_radio_agc_relative_atten_21_db = 0,
at86rf215_radio_agc_relative_atten_24_db = 1,
at86rf215_radio_agc_relative_atten_27_db = 2,
at86rf215_radio_agc_relative_atten_30_db = 3,
at86rf215_radio_agc_relative_atten_33_db = 4,
at86rf215_radio_agc_relative_atten_36_db = 5,
at86rf215_radio_agc_relative_atten_39_db = 6,
at86rf215_radio_agc_relative_atten_41_db = 7,
} at86rf215_radio_agc_relative_atten_en;
typedef struct
{
// commands
int agc_measure_source_not_filtered; // AGC Input (0 - filterred, 1 - unfiltered, faster operation)
at86rf215_radio_agc_averaging_en avg; // AGC Average Time in Number of Samples
int reset_cmd; // AGC Reset - resets the AGC and sets the maximum receiver gain.
int freeze_cmd; // AGC Freeze Control - A value of one forces the AGC to
// freeze to its current value.
int enable_cmd; // AGC Enable - a value of zero allows a manual setting of
// the RX gain control by sub-register AGCS.GCW
at86rf215_radio_agc_relative_atten_en att; // AGC Target Level - sets the AGC target level relative to ADC full scale.
int gain_control_word; // If AGCC_EN is set to 1, a read of bit AGCS.GCW indicates the current
// receiver gain setting. If AGCC_EN is set to 0, a write access to GCW
// manually sets the receiver gain. An integer value of 23 indicates
// the maximum receiver gain; each integer step changes the gain by 3dB.
// status
int freeze_status; // AGC Freeze Status - A value of one indicates that the AGC is on hold.
} at86rf215_radio_agc_ctrl_st;
typedef struct
{
int ext_lna_bypass_available; // The bit activates an AGC scheme where the external LNA
// can be bypassed using pins FEAnn/FEBnn.
int agc_backoff; // 0x00 - no backoff - anyway we do not use this option
int analog_voltage_external; // The bit disables the internal analog supply voltage - requires external LDO
int analog_voltage_enable_in_off; // for fast turn-on from TRXOFF state - the voltage is kept going even when off
int int_power_amplifier_voltage; // 0: 2V, 1: 2.2V, 2: 2.4V;
int fe_pad_configuration; // 2 bits, 4 options pg.73 in datasheet. for Caribou this should be "1"
// 0: no control - pads disabled (always '0')
// 1: FEA|FEB: L|L: TXPREP (Frontend off); H|L: TX (Transmit); L|H: RX (Receive); H|H: RX with LNA Bypass
// 2: FEA|FEB: L|L: TXPREP (Frontend off); H|H: TX (Transmit); L|H: RX (Receive); H|L: RX with LNA Bypass
// 3: FEA|FEB|MCUPin: L|L|L: TXPREP (Frontend off); H|H|H: TX (Transmit); L|H|H: RX (Receive); L|L|H: RX with LNA Bypass
// statuses
int analog_voltage_status;
} at86rf215_radio_external_ctrl_st;
typedef struct
{
int inverter_sign_if; // A value of one configures the receiver to implement the
// inverted-sign IF frequency. Use default setting for normal operation.
int shift_if_freq; // A value of one configures the receiver to shift the IF frequency
// by factor of 1.25. This is useful to place the image frequency according
// to channel scheme.
at86rf215_radio_rx_bw_en bw; // The sub-register controls the receiver filter bandwidth settings.
at86rf215_radio_f_cut_en fcut; // RX filter relative cut-off frequency
at86rf215_radio_sample_rate_en fs; // RX Sample Rate
} at86rf215_radio_set_rx_bw_samp_st;
typedef enum
{
at86rf215_radio_energy_detection_mode_auto = 0,
// Energy detection measurement is automatically triggered if the AGC is held by the internal
// baseband or by setting bit FRZC.
at86rf215_radio_energy_detection_mode_single = 1,
// A single energy detection measurement is started.
at86rf215_radio_energy_detection_mode_continous = 2,
// A continuous energy detection measurements of configured interval defined in
// register EDD is started.
at86rf215_radio_energy_detection_mode_off = 3,
// Energy detection measurement is disabled
} at86rf215_radio_energy_detection_mode_en;
typedef struct
{
// cmd
at86rf215_radio_energy_detection_mode_en mode; // Energy Detection Mode
float average_duration_us; // T[μs]=DF*DTB - the DTB will be calculated accordingly
// status
float energy_detection_value; // Receiver Energy Detection Value
} at86rf215_radio_energy_detection_st;
typedef enum
{
at86rf215_radio_tx_pa_ramp_4usec = 0,
at86rf215_radio_tx_pa_ramp_8usec = 1,
at86rf215_radio_tx_pa_ramp_16usec = 2,
at86rf215_radio_tx_pa_ramp_32usec = 3,
} at86rf215_radio_tx_pa_ramp_en;
typedef enum
{
at86rf215_radio_tx_cut_off_80khz = 0x0,
at86rf215_radio_tx_cut_off_100khz = 0x1,
at86rf215_radio_tx_cut_off_125khz = 0x2,
at86rf215_radio_tx_cut_off_160khz = 0x3,
at86rf215_radio_tx_cut_off_200khz = 0x4,
at86rf215_radio_tx_cut_off_250khz = 0x5,
at86rf215_radio_tx_cut_off_315khz = 0x6,
at86rf215_radio_tx_cut_off_400khz = 0x7,
at86rf215_radio_tx_cut_off_500khz = 0x8,
at86rf215_radio_tx_cut_off_625khz = 0x9,
at86rf215_radio_tx_cut_off_800khz = 0xA,
at86rf215_radio_tx_cut_off_1000khz = 0xB,
} at86rf215_radio_tx_cut_off_en;
typedef enum
{
at86rf215_radio_pa_current_reduction_22ma = 0, // 3dB reduction of gain
at86rf215_radio_pa_current_reduction_18ma = 1, // 2dB reduction of gain
at86rf215_radio_pa_current_reduction_11ma = 2, // 1dB reduction of gain
at86rf215_radio_pa_current_reduction_0ma = 3, // no reduction
} at86rf215_radio_pa_current_reduction_en;
typedef struct
{
at86rf215_radio_tx_pa_ramp_en pa_ramping_time;
at86rf215_radio_pa_current_reduction_en current_reduction;
int tx_power;
// Maximum output power is TXPWR=31, minimum output power is TXPWR=0.
// The output power can be set by about 1dB step resolution.
at86rf215_radio_tx_cut_off_en analog_bw;
at86rf215_radio_f_cut_en digital_bw;
at86rf215_radio_sample_rate_en fs;
int direct_modulation;
} at86rf215_radio_tx_ctrl_st;
typedef enum
{
at86rf215_radio_pll_loop_bw_default = 0,
at86rf215_radio_pll_loop_bw_dec_15perc = 1,
at86rf215_radio_pll_loop_bw_inc_15perc = 2,
} at86rf215_radio_pll_loop_bw_en;
typedef struct
{
at86rf215_radio_pll_loop_bw_en loop_bw;
// This sub-register controls the PLL loop bandwidth.The sub-register is applicable for the sub-1GHz transceiver only
// (RF09). The TX modulation quality (i.e. FSK eye diagram) can be adjusted when direct modulation is used.
int pll_center_freq;
// Center frequency calibration is performed from state TRXOFF to state TXPREP and at channel change. The register
// displays the center frequency value of the current channel.
// statuses
int pll_locked;
} at86rf215_radio_pll_ctrl_st;
void at86rf215_radio_setup_interrupt_mask(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_irq_st* mask);
void at86rf215_radio_setup_external_settings(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_external_ctrl_st* cfg);
void at86rf215_radio_get_external_settings(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_external_ctrl_st* cfg);
at86rf215_radio_state_cmd_en at86rf215_radio_get_state(at86rf215_st* dev, at86rf215_rf_channel_en ch);
void at86rf215_radio_set_state(at86rf215_st* dev, at86rf215_rf_channel_en ch, at86rf215_radio_state_cmd_en cmd);
double at86rf215_radio_get_frequency( /*IN*/ at86rf215_radio_channel_mode_en mode,
/*IN*/ int channel_spacing_25khz_res,
/*IN*/ double wanted_frequency_hz,
/*OUT*/ int *center_freq_25khz_res,
/*OUT*/ int *channel_number);
void at86rf215_radio_setup_channel(at86rf215_st* dev, at86rf215_rf_channel_en ch,
int channel_spacing_25khz_res,
int center_freq_25khz_res,
int channel_number,
at86rf215_radio_channel_mode_en mode);
void at86rf215_radio_set_rx_bandwidth_sampling(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_set_rx_bw_samp_st* cfg);
void at86rf215_radio_get_rx_bandwidth_sampling(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_set_rx_bw_samp_st* cfg);
void at86rf215_radio_setup_agc(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_agc_ctrl_st *agc_ctrl);
void at86rf215_radio_get_agc(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_agc_ctrl_st *agc_ctrl);
float at86rf215_radio_get_rssi_dbm(at86rf215_st* dev, at86rf215_rf_channel_en ch);
void at86rf215_radio_setup_energy_detection(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_energy_detection_st* ed);
void at86rf215_radio_get_energy_detection(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_energy_detection_st* ed);
uint8_t at86rf215_radio_get_random_value(at86rf215_st* dev, at86rf215_rf_channel_en ch);
void at86rf215_radio_setup_tx_ctrl(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_tx_ctrl_st* cfg);
void at86rf215_radio_get_tx_ctrl(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_tx_ctrl_st* cfg);
void at86rf215_radio_setup_pll_ctrl(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_pll_ctrl_st* cfg);
void at86rf215_radio_get_pll_ctrl(at86rf215_st* dev, at86rf215_rf_channel_en ch,
at86rf215_radio_pll_ctrl_st* cfg);
void at86rf215_radio_set_tx_iq_calibration(at86rf215_st* dev, at86rf215_rf_channel_en ch,
int cal_i, int cal_q);
void at86rf215_radio_get_tx_iq_calibration(at86rf215_st* dev, at86rf215_rf_channel_en ch,
int *cal_i, int *cal_q);
void at86rf215_radio_set_tx_dac_input_iq(at86rf215_st* dev, at86rf215_rf_channel_en ch,
int enable_dac_i_dc, int dac_i_val,
int enable_dac_q_dc, int dac_q_val);
void at86rf215_radio_get_tx_dac_input_iq(at86rf215_st* dev, at86rf215_rf_channel_en ch,
int *enable_dac_i_dc, int *dac_i_val,
int *enable_dac_q_dc, int *dac_q_val);
int at86rf215_radio_get_good_channel(double wanted_frequency_hz, at86rf215_radio_channel_mode_en *mode,
at86rf215_rf_channel_en *ch);
#ifdef __cplusplus
}
#endif
#endif // __AT86RF215_RADIO_H__

Wyświetl plik

@ -1,300 +0,0 @@
#ifndef _AT86RF215_REGS_H_
#define _AT86RF215_REGS_H_
#ifdef __cplusplus
extern "C" {
#endif
/*!
* ============================================================================
* AT86RF215 Internal registers Address
* ============================================================================
*/
/* Common settings */
#define REG_RF_RST 0x0005
/* Interrupt registers */
#define REG_RF_CFG 0x0006
#define REG_RF09_IRQS 0x0000
#define REG_RF24_IRQS 0x0001
#define REG_BBC0_IRQS 0x0002
#define REG_BBC1_IRQS 0x0003
#define REG_RF09_IRQM 0x0100
#define REG_RF24_IRQM 0x0200
#define REG_BBC0_IRQM 0x0300
#define REG_BBC1_IRQM 0x0400
/* RF interrupt register values */
#define RF_IRQM_WAKEUP 0x00
#define RF_IRQM_TRXRDY 0x01
#define RF_IRQM_EDC 0x02
#define RF_IRQM_BATLOW 0x03
#define RF_IRQM_TRXERR 0x04
#define RF_IRQM_IQIFSF 0x05
/* BB interrupt register values */
#define BB_INTR_RXFS 0x01
#define BB_INTR_RXFE 0x02
#define BB_INTR_RXAM 0x04
#define BB_INTR_RXEM 0x08
#define BB_INTR_TXFE 0x10
#define BB_INTR_AGCH 0x20
#define BB_INTR_AGCR 0x40
#define BB_INTR_FBLI 0x80
#define REG_RF_IQIFC0 0x000A
#define REG_RF_IQIFC1 0x000B
#define REG_RF_IQIFC2 0x000C
/* Baseband registers */
#define REG_BBC0_TXFLL 0x0306
#define REG_BBC0_TXFLH 0x0307
#define REG_BBC0_FBTXS 0x2800
#define REG_BBC0_FBTXE 0x2FFE
#define REG_BBC0_FSKPHRTX 0x036A
#define REG_BBC0_PC 0x0301
#define REG_BBC0_FSKDM 0x0372
#define REG_BBC1_TXFLL 0x0406
#define REG_BBC1_TXFLH 0x0407
#define REG_BBC1_FBTXS 0x3800
#define REG_BBC1_FBTXE 0x3FFE
#define REG_BBC1_FSKPHRTX 0x046A
#define REG_BBC1_TXDFE 0x0113
#define REG_BBC1_PC 0x0401
#define REG_BBC1_FSKDM 0x0372
/* Common RF */
#define REG_RF09_PLLCF 0x0122
#define REG_RF_CLKO 0x0007
#define RF_CLKO_OFF 0x00
typedef enum
{
at86rf215_drive_current_2ma = 0,
at86rf215_drive_current_4ma = 1,
at86rf215_drive_current_6ma = 2,
at86rf215_drive_current_8ma = 3,
} at86rf215_drive_current_en;
typedef enum
{
at86rf215_clock_out_freq_off = 0,
at86rf215_clock_out_freq_26mhz = 1,
at86rf215_clock_out_freq_32mhz = 2,
at86rf215_clock_out_freq_16mhz = 3,
at86rf215_clock_out_freq_8mhz = 4,
at86rf215_clock_out_freq_4mhz = 5,
at86rf215_clock_out_freq_2mhz = 6,
at86rf215_clock_out_freq_1mhz = 7,
} at86rf215_clock_out_freq_en;
/* bandwidth */
#define REG_RF09_RXBWC 0x0109
#define REG_RF24_RXBWC 0x0209
/* Front end FE Pads */
#define REG_RF09_PADFE 0x0116
#define REG_RF24_PADFE 0x0216
/* different bandwidth values */
#define RF_BW160KHZ_IF250KHZ 0x00
#define RF_BW200KHZ_IF250KHZ 0x01
#define RF_BW250KHZ_IF250KHZ 0x02
#define RF_BW320KHZ_IF500KHZ 0x03
#define RF_BW400KHZ_IF500KHZ 0x04
#define RF_BW500KHZ_IF500KHZ 0x05
#define RF_BW630KHZ_IF1000KHZ 0x06
#define RF_BW800KHZ_IF1000KHZ 0x07
#define RF_BW1000KHZ_IF1000KHZ 0x08
#define RF_BW1250KHZ_IF2000KHZ 0x09
#define RF_BW1600KHZ_IF2000KHZ 0x0A
#define RF_BW2000KHZ_IF2000KHZ 0x0B
#define RF_BW2000KHZ_IFCCKHZ 0x0C
#define RF_BW2000KHZ_IFDDHZ 0x0D
#define RF_BW2000KHZ_IFEEKHZ 0x0E
#define RF_BW2000KHZ_IFFFKHZ 0x0F
/* different Skew values */
#define RF_IQ_SKEW_pos_2 0x00
#define RF_IQ_SKEW_pos_1 0x01
#define RF_IQ_SKEW_zero 0x02
#define RF_IQ_SKEW_neg_1 0x03
/* CMV values */
#define RF_IQ_LVDS_CMV150 0x00
#define RF_IQ_LVDS_CMV200 0x01
#define RF_IQ_LVDS_CMV250 0x02
#define RF_IQ_LVDS_CMV300 0x03
/* IQ drive current */
#define RF_IQ_DRV_Current_1mA 0x00
#define RF_IQ_DRV_Current_2mA 0x01
#define RF_IQ_DRV_Current_3mA 0x02
#define RF_IQ_DRV_Current_4mA 0x03
/* different IFS values */
#define RX_IFS_Deactive 0x00
#define RX_IFS_Active 0x01
/* sampling rate */
#define REG_RF09_RXDFE 0x010A
#define REG_RF24_RXDFE 0x020A
/* different sampling rate values */
#define RF_SR4000 0x01
#define RF_SR2000 0x02
#define RF_SR1333 0x03
#define RF_SR1000 0x04
#define RF_SR800 0x05
#define RF_SR666 0x06
#define RF_SR500 0x08
#define RF_SR400 0x0A
/* RX filter relative cut-off frequency */
#define RF_CUT_1_4 0x00
#define RF_CUT_3_8 0x01
#define RF_CUT_1_2 0x02
#define RF_CUT_3_4 0x03
#define RF_CUT_4_4 0x04
/* AGC */
#define REG_RF09_AGCC 0x010B
#define REG_RF09_AGCS 0x010C
#define REG_RF24_AGCC 0x020B
#define REG_RF24_AGCS 0x020C
/* AGC values */
/* AGC average sampling */
#define RF_AGC_AVGS_8 0x00
#define RF_AGC_AVGS_16 0x01
#define RF_AGC_AVGS_32 0x02
#define RF_AGC_AVGS_64 0x03
/* Chip mode */
#define RF_MODE_BBRF 0x00
#define RF_MODE_RF 0x01
#define RF_MODE_BBRF09 0x04
#define RF_MODE_BBRF24 0x05
/* Transceiver operation commands */
#define RF_CMD_NOP 0x00
#define RF_CMD_SLEEP 0x01
#define RF_CMD_TRXOFF 0x02
#define RF_CMD_TXPREP 0x03
#define RF_CMD_TX 0x04
#define RF_CMD_RX 0x05
#define RF_CMD_RESET 0x07
/* Transceiver Baseband PHY type, combined BBEN and PT part of PHY Control register */
#define BB_PHY_PHYOFF 0x00
#define BB_PHY_FSK 0x05
#define BB_PHY_OFDM 0x06
#define BB_PHY_OQPSK 0x07
/* Transceiver interface mode */
#define RF_MODE_BBRF 0x00
#define RF_MODE_RF 0x01
#define RF_MODE_BBRF09 0x04
#define RF_MODE_BBRF24 0x05
/* Oscillator settings */
#define REG_RF_XOC 0x0009
/* Command */
/* RF09 Radio */
#define REG_RF09_AUXS 0x0101
#define REG_RF09_STATE 0x0102
#define REG_RF09_CMD 0x0103
#define REG_RF09_PAC 0x0114
#define REG_RF09_TXDFE 0x0113
/* RF24 Radio */
#define REG_RF24_AUXS 0x0201
#define REG_RF24_CMD 0x0203
#define REG_RF24_STATE 0x0202
#define REG_RF24_PAC 0x0214
#define REG_RF24_TXDFE 0x0213
/* power levels */
#define RF_TXPWR_00 0x00 //-21.4dBm
#define RF_TXPWR_01 0x01 //-20.4dBm
#define RF_TXPWR_10 0x10 //
#define RF_TXPWR_MAX 0x1F //
/* power amplifier current reduction */
#define RF_PAC_3dB_Reduction 0x00
#define RF_PAC_2dB_Reduction 0x01
#define RF_PAC_1dB_Reduction 0x02
#define RF_PAC_0dB_Reduction 0x03
/* power amplifier DC voltage */
#define RF_PA_VC_2_0 0x00
#define RF_PA_VC_2_2 0x01
#define RF_PA_VC_2_4 0x02
/* frequency registers */
/* 900MHz */
#define REG_RF09_CS 0x0104
#define REG_RF09_CCF0L 0x0105
#define REG_RF09_CCF0H 0x0106
#define REG_RF09_CNL 0x0107
#define REG_RF09_CNM 0x0108
/* 2400MHz */
#define REG_RF24_CS 0x0204
#define REG_RF24_CCF0L 0x0205
#define REG_RF24_CCF0H 0x0206
#define REG_RF24_CNL 0x0207
#define REG_RF24_CNM 0x0208
/* Calibration registers */
/* RF09 Interface */
#define REG_RF09_TXCI 0x0125
#define REG_RF09_TXCQ 0x0126
/* RF24 Interface */
#define REG_RF24_TXCI 0x0225
#define REG_RF24_TXCQ 0x0226
/* RF24 Radio */
#define REG_RF24_CMD 0x0203
/* I/O settings */
/* Version */
#define REG_RF_VN 0x000E
#define REG_RF_PN 0x000D
typedef enum
{
at86rf215_pn_at86rf215 = 0x34,
at86rf215_pn_at86rf215iq = 0x35,
at86rf215_pn_at86rf215m = 0x36,
} at86rf215_pn_en;
/* Additional settings */
/*!
* ============================================================================
* Timing Definitions
* Timings are define in nano seconds
* Page 189 datasheet
* ============================================================================
*/
#define T_TRXOFF_TXPREP_ns 200
#define T_TXPREP_TRXOFF_ns 200
#define T_TXPREP_TX_ns 200
#define T_TXPREP_RX_ns 200
#define T_TX_TXPREP_TXFE_ns 200
#define T_TX_TXPREP_CMD_us 33 //assuming PA ramp 3
#define T_RX_TXPREP_ns 200
#define T_TX_Start_Delay_us 4
#ifdef __cplusplus
}
#endif
#endif

Wyświetl plik

@ -1,284 +0,0 @@
#include <stdio.h>
#include "at86rf215.h"
#include "at86rf215_radio.h"
#include "io_utils/io_utils.h"
#include "io_utils/io_utils_spi.h"
#define CARIBOULITE_MOSI 20
#define CARIBOULITE_SCK 21
#define CARIBOULITE_MISO 19
#define FPGA_RESET 26
#define ICE40_CS 18
#define MIXER_RESET 5
#define CARIBOULITE_SPI_DEV 1
#define CARIBOULITE_MODEM_SPI_CHANNEL 1
#define CARIBOULITE_MODEM_SS 17
#define CARIBOULITE_MODEM_RESET 23
#define CARIBOULITE_MODEM_IRQ 22
io_utils_spi_st io_spi_dev =
{
.miso = CARIBOULITE_MISO,
.mosi = CARIBOULITE_MOSI,
.sck = CARIBOULITE_SCK,
};
at86rf215_st dev =
{
.reset_pin = CARIBOULITE_MODEM_RESET,
.irq_pin = CARIBOULITE_MODEM_IRQ,
.cs_pin = CARIBOULITE_MODEM_SS,
.spi_dev = CARIBOULITE_SPI_DEV,
.spi_channel = CARIBOULITE_MODEM_SPI_CHANNEL,
};
uint16_t unknown_regs[] = { 0x0015,
0x0115, 0x0117, 0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F, 0x0120, 0x0123, 0x0124, 0x0129,
0x0215, 0x0217, 0x0218, 0x0219, 0x021A, 0x021B, 0x021C, 0x021D, 0x021E, 0x021F, 0x0220, 0x0223, 0x0224, 0x0229};
uint8_t defaults[] = { 0x0E,
0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0f, 0x0f, 0x08,
0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0f, 0x0f, 0x08};
// -----------------------------------------------------------------------------------------
// This test checks the version number and part numbers of the device
int test_at86rf215_read_all_regs(at86rf215_st* dev)
{
for (uint16_t reg = 0; reg < 0x300; reg ++)
{
uint8_t val = at86rf215_read_byte(dev, reg);
printf("REG #0x%04X : 0x%02X\n", reg, val);
}
return 0;
}
int test_at86rf215_read_all_regs_check(at86rf215_st* dev)
{
int num_regs = sizeof(unknown_regs) / sizeof(uint16_t);
for (int i = 0; i < num_regs; i ++)
{
uint8_t val = at86rf215_read_byte(dev, unknown_regs[i]);
if (val != defaults[i]) printf("REG #0x%04X : 0x%02X (instead of 0x%02X)\n", unknown_regs[i], val, defaults[i]);
}
return 0;
}
// -----------------------------------------------------------------------------------------
// This test checks the version number and part numbers of the device
int test_at86rf215_read_chip_vn_pn(at86rf215_st* dev)
{
int pass = 0;
uint8_t pn, vn;
char pn_st[15] = {0};
at86rf215_get_versions(dev, &pn, &vn);
if (pn==0x34 && vn > 0 && vn < 5) pass = 1;
if (pn==0x34)
sprintf(pn_st, "AT86RF215");
else if (pn==0x35)
sprintf(pn_st, "AT86RF215IQ");
else if (pn==0x36)
sprintf(pn_st, "AT86RF215M");
else
sprintf(pn_st, "UNKNOWN");
printf("TEST:AT86RF215:VERSIONS:PN=0x%02X\n", pn);
printf("TEST:AT86RF215:VERSIONS:VN=%d\n", vn);
printf("TEST:AT86RF215:VERSIONS:PASS=%d\n", pass);
printf("TEST:AT86RF215:VERSIONS:INFO=The component PN is %s (0x%02X), Version %d\n", pn_st, pn, vn);
at86rf215_set_clock_output(dev, at86rf215_drive_current_8ma, at86rf215_clock_out_freq_32mhz);
return pass;
}
// -----------------------------------------------------------------------------------------
// This test performs a frequency sweep on a certain channel:
// at86rf215_rf_channel_900mhz / at86rf215_rf_channel_2400mhz
// and does it from "start_freq" to "start_freq + num_freq * step_freq"
// usec_gaps - specifies the micro-second gaps between freq steps or '-1' that
// tell the function to put "getchars" (wait for enter key)
void test_at86rf215_sweep_frequencies(at86rf215_st* dev,
at86rf215_rf_channel_en channel,
int start_freq,
int num_freq,
int step_freq,
int usec_gaps)
{
char channel_name[10];
if (channel == at86rf215_rf_channel_900mhz)
sprintf(channel_name, "900MHz");
else sprintf(channel_name, "2400MHz");
io_utils_usleep(usec_gaps);
int stop_freq = start_freq + step_freq*num_freq;
int f = start_freq;
while (f <= stop_freq)
{
printf("TEST:AT86RF215:FREQ_SWEEP:FREQ=%.2fMHz, CH=%s)\n", ((float)f) / 1e6, channel_name);
at86rf215_setup_iq_radio_dac_value_override (dev,
channel,
f,
31);
//printf("Press enter to switch\n");
if (usec_gaps > 0) io_utils_usleep(usec_gaps);
else
{
printf("Press enter to step...\n");
getchar();
}
//test_at86rf215_read_all_regs_check(dev);
f += step_freq;
}
// back to TX off state
at86rf215_radio_set_state(dev, at86rf215_rf_channel_900mhz, at86rf215_radio_state_cmd_trx_off);
}
// -----------------------------------------------------------------------------------------
// Starting a reception window
// usec_timeout - set up a timeout value in micro-seconds or -1 to wait for "enter" key
int test_at86rf215_continues_iq_rx (at86rf215_st* dev, at86rf215_rf_channel_en radio,
uint64_t freq_hz, int usec_timeout)
{
at86rf215_iq_clock_data_skew_en skew = radio == at86rf215_rf_channel_900mhz?
at86rf215_iq_clock_data_skew_4_906ns:
at86rf215_iq_clock_data_skew_4_906ns;
at86rf215_setup_iq_radio_receive (dev, radio, freq_hz, 0, skew);
printf("Started I/Q RX session for Radio %d, Freq: %llu Hz, timeout: %d usec (0=infinity)\n",
radio, freq_hz, usec_timeout);
test_at86rf215_read_all_regs_check(dev);
if (usec_timeout>0)
{
io_utils_usleep(usec_timeout);
}
else
{
printf("Press enter to stop...\n");
getchar();
}
at86rf215_stop_iq_radio_receive (dev, radio);
test_at86rf215_read_all_regs_check(dev);
return 1;
}
// -----------------------------------------------------------------------------------------
// SMI communication tesing with loopback
// usec_timeout - set up a timeout value in micro-seconds or -1 to wait for "enter" key
int test_at86rf215_continues_iq_loopback (at86rf215_st* dev, at86rf215_rf_channel_en radio,
uint32_t freq_hz, int usec_timeout)
{
at86rf215_setup_iq_radio_receive (dev, radio, freq_hz, 0, at86rf215_iq_clock_data_skew_4_906ns);
//at86rf215_radio_set_tx_dac_input_iq(dev, radio, 1, 0x7E, 1, 0x3F);
printf("Started I/Q RX session for Radio %d, Freq: %d Hz, timeout: %d usec (0=infinity)\n",
radio, freq_hz, usec_timeout);
if (usec_timeout>0)
{
io_utils_usleep(usec_timeout);
}
else
{
printf("Press enter to stop...\n");
getchar();
}
at86rf215_stop_iq_radio_receive (dev, radio);
return 1;
}
// -----------------------------------------------------------------------------------------
// TEST SELECTION
// -----------------------------------------------------------------------------------------
#define NO_FPGA_MODE 1
#define TEST_VERSIONS 1
#define TEST_FREQ_SWEEP 0
#define TEST_IQ_RX_WIND 1
#define TEST_IQ_RX_WIND_RAD 0
#define TEST_IQ_LB_WIND 0
#define TEST_READ_ALL_REGS 0
// -----------------------------------------------------------------------------------------
// MAIN
// -----------------------------------------------------------------------------------------
int main ()
{
at86rf215_iq_interface_config_st cfg = {0};
at86rf215_irq_st irq = {0};
// Init GPIOs and set FPGA on reset
io_utils_setup();
#if NO_FPGA_MODE
// When the FPGA wakes up non-programmed, it starts interogating
// the SPI interface for SPI-Flash hosted firmware. This process
// interfered with other bus users. Thus in the case that the FPGA
// is not progreammed, we need it to be in RESET state.
// As soon as the FPGA is programmed, it behaves and doesn't interfere
// anymore with other ICs so this code is not anymore relevant.
io_utils_set_gpio_mode(FPGA_RESET, io_utils_alt_gpio_out);
io_utils_set_gpio_mode(ICE40_CS, io_utils_alt_gpio_out);
io_utils_write_gpio(FPGA_RESET, 0);
io_utils_write_gpio(ICE40_CS, 0);
io_utils_set_gpio_mode(MIXER_RESET, io_utils_alt_gpio_out);
io_utils_write_gpio(MIXER_RESET, 0);
#endif
// Init spi
io_utils_spi_init(&io_spi_dev);
at86rf215_reset(&dev);
at86rf215_init(&dev, &io_spi_dev);
io_utils_spi_print_setup(&io_spi_dev);
test_at86rf215_read_all_regs_check(&dev);
// TEST: read the p/n and v/n from the IC
#if TEST_VERSIONS
test_at86rf215_read_chip_vn_pn(&dev);
#endif // TEST_VERSIONS
// TEST: Frequency sweep
#if TEST_FREQ_SWEEP
test_at86rf215_sweep_frequencies(&dev, at86rf215_rf_channel_900mhz, 900e6, 3, 10, 10000);
#endif // TEST_FREQ_SWEEP
#if TEST_IQ_RX_WIND
#if TEST_IQ_RX_WIND_RAD==0
test_at86rf215_continues_iq_rx (&dev, at86rf215_rf_channel_900mhz, 900e6, -1);
#else
test_at86rf215_continues_iq_rx (&dev, at86rf215_rf_channel_2400mhz, 2400e6, -1);
#endif
#endif // TEST_IQ_RX_WIND
#if TEST_IQ_LB_WIND
test_at86rf215_continues_iq_loopback (&dev, at86rf215_rf_channel_900mhz, 900e6, -1);
#endif
#if TEST_READ_ALL_REGS
test_at86rf215_read_all_regs_check(&dev);
#endif
at86rf215_close(&dev);
io_utils_spi_close(&io_spi_dev);
io_utils_cleanup();
return 0;
}

Wyświetl plik

@ -1,2 +0,0 @@
# build directories
build

Wyświetl plik

@ -1,28 +0,0 @@
cmake_minimum_required(VERSION 3.15)
project(cariboulite)
set(CMAKE_BUILD_TYPE Release)
# Bring the headers
set(SUPER_DIR ${PROJECT_SOURCE_DIR}/..)
include_directories(/.)
include_directories(${SUPER_DIR})
# Source files
set(SOURCES_LIB caribou_fpga.c)
set(SOURCES ${SOURCES_LIB} test_caribou_fpga.c)
set(EXTERN_LIBS
${SUPER_DIR}/io_utils/build/libio_utils.a
${SUPER_DIR}/caribou_programming/build/libcaribou_prog.a
${SUPER_DIR}/zf_log/build/libzf_log.a
-lpthread)
#add_compile_options(-Wall -Wextra -pedantic -Werror)
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-missing-braces)
#Generate the static library from the sources
add_library(caribou_fpga STATIC ${SOURCES_LIB})
#add_executable(test_caribou_fpga ${SOURCES})
#target_link_libraries(test_caribou_fpga rt pthread ${EXTERN_LIBS})
# Set the location for library installation -- i.e., /usr/lib in this case
# not really necessary in this example. Use "sudo make install" to apply
install(TARGETS caribou_fpga DESTINATION /usr/lib)

Wyświetl plik

@ -1,618 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "FPGA"
#include "zf_log/zf_log.h"
#include <stdio.h>
#include <string.h>
#include "caribou_fpga.h"
//--------------------------------------------------------------
// Static Definitions
//--------------------------------------------------------------
#define IOC_MOD_VER 0
#define IOC_SYS_CTRL_SYS_VERSION 1
#define IOC_SYS_CTRL_MANU_ID 2
#define IOC_SYS_CTRL_SYS_ERR_STAT 3
#define IOC_SYS_CTRL_SYS_SOFT_RST 4
#define IOC_SYS_CTRL_DEBUG_MODES 5
#define IOC_SYS_CTRL_SYS_TX_SAMPLE_GAP 6
#define IOC_IO_CTRL_MODE 1
#define IOC_IO_CTRL_DIG_PIN 2
#define IOC_IO_CTRL_PMOD_DIR 3
#define IOC_IO_CTRL_PMOD_VAL 4
#define IOC_IO_CTRL_RF_PIN 5
#define IOC_IO_CTRL_MXR_FM_PS 6
#define IOC_IO_CTRL_MXR_FM_DATA 7
#define IOC_SMI_CTRL_FIFO_STATUS 1
#define IOC_SMI_CHANNEL_SELECT 2
#define IOC_SMI_CTRL_DIR_SELECT 3
//--------------------------------------------------------------
// Internal Data-Types
//--------------------------------------------------------------
#pragma pack(1)
typedef enum
{
caribou_fpga_rw_read = 0,
caribou_fpga_rw_write = 1,
} caribou_fpga_rw_en;
typedef enum
{
caribou_fpga_mid_sys_ctrl = 0,
caribou_fpga_mid_io_ctrl = 1,
caribou_fpga_mid_smi_ctrl = 2,
caribou_fpga_mid_res = 3,
} caribou_fpga_mid_en;
typedef struct
{
uint8_t ioc : 5;
caribou_fpga_mid_en mid : 2;
caribou_fpga_rw_en rw : 1; // MSB
} caribou_fpga_opcode_st;
#pragma pack()
#define CARIBOU_FPGA_CHECK_DEV(d,f) \
{ \
if ((d)==NULL) { ZF_LOGE("%s: dev is NULL", (f)); return -1;} \
if (!(d)->initialized) {ZF_LOGE("%s: dev not initialized", (f)); return -1;} \
}
#define CARIBOU_FPGA_CHECK_PTR_NOT_NULL(p,f,n) {if ((p)==NULL) {ZF_LOGE("%s: %s is NULL",(f),(n)); return -1;}}
//===================================================================
void caribou_fpga_interrupt_handler (int event, int level, uint32_t tick, void *data)
{
//int i;
//caribou_fpga_st* dev = (caribou_fpga_st*)data;
/*for (i=0; i<e; i++)
{
printf("u=%d t=%"PRIu64" c=%d g=%d l=%d f=%d (%d of %d)\n",
dev, evt[i].report.timestamp, evt[i].report.chip,
evt[i].report.gpio, evt[i].report.level,
evt[i].report.flags, i+1, e);
}*/
}
//--------------------------------------------------------------
static int caribou_fpga_spi_transfer (caribou_fpga_st* dev, uint8_t *opcode, uint8_t *data)
{
uint8_t tx_buf[2] = {*opcode, *data};
uint8_t rx_buf[2] = {0, 0};
int ret = io_utils_spi_transmit(dev->io_spi, dev->io_spi_handle,
tx_buf, rx_buf, 2, io_utils_spi_read_write);
if (ret<0)
{
ZF_LOGE("spi transfer failed (%d)", ret);
return -1;
}
// on success return 0 (the number of transmitted bytes are same as needed),
// otherwise '1' (warning / error)
*data = rx_buf[1];
return !(ret == sizeof(rx_buf));
}
//--------------------------------------------------------------
int caribou_fpga_init(caribou_fpga_st* dev, io_utils_spi_st* io_spi)
{
if (dev == NULL)
{
ZF_LOGE("dev is NULL");
return -1;
}
dev->io_spi = io_spi;
ZF_LOGD("configuring reset and irq pins");
// Configure GPIO pins
io_utils_setup_gpio(dev->reset_pin, io_utils_dir_output, io_utils_pull_up);
io_utils_setup_gpio(dev->soft_reset_pin, io_utils_dir_output, io_utils_pull_up);
// set to known state
io_utils_write_gpio(dev->soft_reset_pin, 1);
ZF_LOGD("Initializing io_utils_spi");
io_utils_hard_spi_st hard_dev_fpga = { .spi_dev_id = dev->spi_dev,
.spi_dev_channel = dev->spi_channel, };
dev->io_spi_handle = io_utils_spi_add_chip(dev->io_spi, dev->cs_pin, 1000000, 0, 0,
io_utils_spi_chip_type_fpga_comm,
&hard_dev_fpga);
// Init FPGA programming
if (caribou_prog_init(&dev->prog_dev, dev->io_spi) < 0)
{
ZF_LOGE("ice40 programmer init failed");
return -1;
}
dev->initialized = 1;
return 0;
}
//--------------------------------------------------------------
int caribou_fpga_get_status(caribou_fpga_st* dev, caribou_fpga_status_en *stat)
{
int retries = 3;
int inner_stat = caribou_fpga_status_not_programmed;
while (retries-- && inner_stat != caribou_fpga_status_operational)
{
caribou_fpga_get_versions (dev, NULL);
if (dev->versions.sys_manu_id != CARIBOU_SDR_MANU_CODE)
{
inner_stat = caribou_fpga_status_not_programmed;
//caribou_fpga_print_versions (dev);
caribou_fpga_soft_reset(dev);
io_utils_usleep(20000);
}
else
{
inner_stat = caribou_fpga_status_operational;
}
}
dev->status = inner_stat;
if (stat) *stat = dev->status;
return 0;
}
//--------------------------------------------------------------
int caribou_fpga_program_to_fpga(caribou_fpga_st* dev, unsigned char *buffer, size_t len, bool force_prog)
{
int prog_retries = 3;
caribou_fpga_get_status(dev, NULL);
if (dev->status == caribou_fpga_status_not_programmed || force_prog)
{
if (buffer == NULL || len == 0)
{
ZF_LOGE("buffer should be not NULL and len > 0");
return -1;
}
while (prog_retries--)
{
if (caribou_prog_configure_from_buffer(&dev->prog_dev, buffer, len) != 0)
{
continue;
}
//caribou_fpga_soft_reset(dev);
io_utils_usleep(100000);
caribou_fpga_get_status(dev, NULL);
if (dev->status == caribou_fpga_status_operational)
{
break;
}
}
if (prog_retries == 0)
{
ZF_LOGE("Programming failed");
return -1;
}
}
else
{
ZF_LOGI("FPGA already operational - not programming (use 'force_prog=true' to force update)");
}
return 0;
}
//--------------------------------------------------------------
int caribou_fpga_program_to_fpga_from_file(caribou_fpga_st* dev, char *filename, bool force_prog)
{
caribou_fpga_get_status(dev, NULL);
if (dev->status == caribou_fpga_status_not_programmed || force_prog)
{
if (caribou_prog_configure(&dev->prog_dev, filename) < 0)
{
ZF_LOGE("Programming failed");
return -1;
}
caribou_fpga_soft_reset(dev);
io_utils_usleep(100000);
caribou_fpga_get_status(dev, NULL);
if (dev->status == caribou_fpga_status_not_programmed)
{
ZF_LOGE("Programming failed");
return -1;
}
}
else
{
ZF_LOGI("FPGA already operational - not programming (use 'force_prog=true' to force update)");
}
return 0;
}
//--------------------------------------------------------------
int caribou_fpga_close(caribou_fpga_st* dev)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_close");
dev->initialized = 0;
io_utils_spi_remove_chip(dev->io_spi, dev->io_spi_handle);
return caribou_prog_release(&dev->prog_dev);
}
//--------------------------------------------------------------
int caribou_fpga_soft_reset(caribou_fpga_st* dev)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_soft_reset");
io_utils_write_gpio_with_wait(dev->soft_reset_pin, 0, 1000);
io_utils_usleep(1000);
io_utils_write_gpio_with_wait(dev->soft_reset_pin, 1, 1000);
io_utils_usleep(20000);
return 0;
}
//--------------------------------------------------------------
int caribou_fpga_hard_reset(caribou_fpga_st* dev)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_hard_reset (disposing firmware)");
io_utils_write_gpio_with_wait(dev->reset_pin, 0, 1000);
io_utils_write_gpio_with_wait(dev->reset_pin, 1, 1000);
return 0;
}
//--------------------------------------------------------------
int caribou_fpga_hard_reset_keep(caribou_fpga_st* dev, bool reset)
{
if (reset)
{
io_utils_write_gpio_with_wait(dev->reset_pin, 0, 1000);
}
else
{
io_utils_write_gpio_with_wait(dev->reset_pin, 1, 1000);
}
return 0;
}
//--------------------------------------------------------------
// System Controller
void caribou_fpga_print_versions (caribou_fpga_st* dev)
{
printf("FPGA Versions:\n");
printf(" System Version: %02X\n", dev->versions.sys_ver);
printf(" Manu. ID: %02X\n", dev->versions.sys_manu_id);
printf(" Sys. Ctrl Version: %02X\n", dev->versions.sys_ctrl_mod_ver);
printf(" IO Ctrl Version: %02X\n", dev->versions.io_ctrl_mod_ver);
printf(" SMI Ctrl Version: %02X\n", dev->versions.smi_ctrl_mod_ver);
}
//--------------------------------------------------------------
int caribou_fpga_get_versions (caribou_fpga_st* dev, caribou_fpga_versions_st* vers)
{
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_read,
.mid = caribou_fpga_mid_sys_ctrl,
};
uint8_t *poc = (uint8_t*)&oc;
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_get_versions");
oc.ioc = IOC_SYS_CTRL_SYS_VERSION;
caribou_fpga_spi_transfer (dev, poc, &dev->versions.sys_ver);
oc.ioc = IOC_SYS_CTRL_MANU_ID;
caribou_fpga_spi_transfer (dev, poc, &dev->versions.sys_manu_id);
oc.ioc = IOC_MOD_VER;
oc.mid = caribou_fpga_mid_sys_ctrl;
caribou_fpga_spi_transfer (dev, poc, &dev->versions.sys_ctrl_mod_ver);
oc.mid = caribou_fpga_mid_io_ctrl;
caribou_fpga_spi_transfer (dev, poc, &dev->versions.io_ctrl_mod_ver);
oc.mid = caribou_fpga_mid_smi_ctrl;
caribou_fpga_spi_transfer (dev, poc, &dev->versions.smi_ctrl_mod_ver);
//caribou_fpga_print_versions (dev);
if (vers)
{
memcpy (vers, &dev->versions, sizeof(caribou_fpga_versions_st));
}
return 0;
}
//--------------------------------------------------------------
static char caribou_fpga_mode_names[][64] =
{
"Low Power (0)",
"RX / TX bypass (1)",
"RX lowpass (up-conversion) (2)",
"RX hipass (down-conversion) (3)",
"TX lowpass (down-conversion) (4)",
"RX hipass (up-conversion) (5)",
};
char* caribou_fpga_get_mode_name (caribou_fpga_io_ctrl_rfm_en mode)
{
if (mode >= caribou_fpga_io_ctrl_rfm_low_power && mode <= caribou_fpga_io_ctrl_rfm_tx_hipass)
return caribou_fpga_mode_names[mode];
return NULL;
}
//--------------------------------------------------------------
int caribou_fpga_set_debug_modes (caribou_fpga_st* dev, bool dbg_fifo_push, bool dbg_fifo_pull, bool dbg_smi)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_set_debug_modes");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_write,
.mid = caribou_fpga_mid_sys_ctrl,
.ioc = IOC_SYS_CTRL_DEBUG_MODES
};
uint8_t mode = ((dbg_fifo_push & 0x1) << 0) | ((dbg_fifo_pull & 0x1) << 1) | ((dbg_smi & 0x1) << 2 );
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), &mode);
}
//--------------------------------------------------------------
int caribou_fpga_get_errors (caribou_fpga_st* dev, uint8_t *err_map)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_get_errors");
CARIBOU_FPGA_CHECK_PTR_NOT_NULL(err_map,"caribou_fpga_get_errors","err_map");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_read,
.mid = caribou_fpga_mid_sys_ctrl,
.ioc = IOC_SYS_CTRL_SYS_ERR_STAT
};
*err_map = 0;
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), err_map);
}
//--------------------------------------------------------------
int caribou_fpga_set_sys_ctrl_tx_sample_gap (caribou_fpga_st* dev, uint8_t gap)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_set_sys_ctrl_tx_sample_gap");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_write,
.mid = caribou_fpga_mid_sys_ctrl,
.ioc = IOC_SYS_CTRL_SYS_TX_SAMPLE_GAP,
};
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), &gap);
}
//--------------------------------------------------------------
int caribou_fpga_get_sys_ctrl_tx_sample_gap (caribou_fpga_st* dev, uint8_t *gap)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_get_sys_ctrl_tx_sample_gap");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_read,
.mid = caribou_fpga_mid_sys_ctrl,
.ioc = IOC_SYS_CTRL_SYS_TX_SAMPLE_GAP
};
*gap = 0;
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), gap);
}
// I/O Controller
int caribou_fpga_set_io_ctrl_mode (caribou_fpga_st* dev, uint8_t debug_mode, caribou_fpga_io_ctrl_rfm_en rfm)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_set_io_ctrl_mode");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_write,
.mid = caribou_fpga_mid_io_ctrl,
.ioc = IOC_IO_CTRL_MODE
};
uint8_t mode = (debug_mode << 0) | (rfm&0x7)<<2;
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), &mode);
}
//--------------------------------------------------------------
int caribou_fpga_get_io_ctrl_mode (caribou_fpga_st* dev, uint8_t* debug_mode, caribou_fpga_io_ctrl_rfm_en* rfm)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_get_io_ctrl_mode");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_read,
.mid = caribou_fpga_mid_io_ctrl,
.ioc = IOC_IO_CTRL_MODE
};
uint8_t mode = 0;
caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), &mode);
*debug_mode = mode & 0x3;
*rfm = (mode >> 2) & 0x7;
return 0;
}
//--------------------------------------------------------------
int caribou_fpga_set_io_ctrl_dig (caribou_fpga_st* dev, int led0, int led1)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_set_io_ctrl_dig");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_write,
.mid = caribou_fpga_mid_io_ctrl,
.ioc = IOC_IO_CTRL_DIG_PIN
};
uint8_t pins = led1<<1 | led0<<0;
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), &pins);
}
//--------------------------------------------------------------
int caribou_fpga_get_io_ctrl_dig (caribou_fpga_st* dev, int* led0, int* led1, int* btn, int* cfg)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_get_io_ctrl_dig");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_read,
.mid = caribou_fpga_mid_io_ctrl,
.ioc = IOC_IO_CTRL_DIG_PIN
};
uint8_t pins = 0;
caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), &pins);
if (led0) *led0 = (pins>>0)&0x01;
if (led1) *led1 = (pins>>1)&0x01;
if (cfg) *cfg = (pins>>3)&0x0F;
if (btn) *btn = (pins>>7)&0x01;
return 0;
}
//--------------------------------------------------------------
int caribou_fpga_set_io_ctrl_pmod_dir (caribou_fpga_st* dev, uint8_t dir)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_set_io_ctrl_pmod_dir");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_write,
.mid = caribou_fpga_mid_io_ctrl,
.ioc = IOC_IO_CTRL_PMOD_DIR
};
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), &dir);
}
//--------------------------------------------------------------
int caribou_fpga_get_io_ctrl_pmod_dir (caribou_fpga_st* dev, uint8_t *dir)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_get_io_ctrl_pmod_dir");
CARIBOU_FPGA_CHECK_PTR_NOT_NULL(dir,"caribou_fpga_get_io_ctrl_pmod_dir","dir");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_read,
.mid = caribou_fpga_mid_io_ctrl,
.ioc = IOC_IO_CTRL_PMOD_DIR
};
*dir = 0;
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), dir);
}
//--------------------------------------------------------------
int caribou_fpga_set_io_ctrl_pmod_val (caribou_fpga_st* dev, uint8_t val)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_set_io_ctrl_pmod_val");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_write,
.mid = caribou_fpga_mid_io_ctrl,
.ioc = IOC_IO_CTRL_PMOD_VAL
};
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), &val);
}
//--------------------------------------------------------------
int caribou_fpga_get_io_ctrl_pmod_val (caribou_fpga_st* dev, uint8_t *val)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_get_io_ctrl_pmod_val");
CARIBOU_FPGA_CHECK_PTR_NOT_NULL(val,"caribou_fpga_get_io_ctrl_pmod_val","val");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_read,
.mid = caribou_fpga_mid_io_ctrl,
.ioc = IOC_IO_CTRL_PMOD_VAL
};
*val = 0;
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), val);
}
//--------------------------------------------------------------
int caribou_fpga_set_io_ctrl_rf_state (caribou_fpga_st* dev, caribou_fpga_rf_pin_st *pins)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_set_io_ctrl_rf_state");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_write,
.mid = caribou_fpga_mid_io_ctrl,
.ioc = IOC_IO_CTRL_RF_PIN
};
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), (uint8_t*)pins);
}
//--------------------------------------------------------------
int caribou_fpga_get_io_ctrl_rf_state (caribou_fpga_st* dev, caribou_fpga_rf_pin_st *pins)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_get_io_ctrl_rf_state");
CARIBOU_FPGA_CHECK_PTR_NOT_NULL(pins,"caribou_fpga_get_io_ctrl_rf_state","pins");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_read,
.mid = caribou_fpga_mid_io_ctrl,
.ioc = IOC_IO_CTRL_RF_PIN
};
memset(pins, 0, sizeof(caribou_fpga_rf_pin_st));
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), (uint8_t*)pins);
}
//--------------------------------------------------------------
int caribou_fpga_get_smi_ctrl_fifo_status (caribou_fpga_st* dev, caribou_fpga_smi_fifo_status_st *status)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_get_smi_ctrl_fifo_status");
CARIBOU_FPGA_CHECK_PTR_NOT_NULL(status,"caribou_fpga_get_smi_ctrl_fifo_status","status");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_read,
.mid = caribou_fpga_mid_smi_ctrl,
.ioc = IOC_SMI_CTRL_FIFO_STATUS
};
memset(status, 0, sizeof(caribou_fpga_smi_fifo_status_st));
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), (uint8_t*)status);
}
//--------------------------------------------------------------
int caribou_fpga_set_smi_channel (caribou_fpga_st* dev, caribou_fpga_smi_channel_en channel)
{
uint8_t val = 0;
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_set_smi_channel");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_write,
.mid = caribou_fpga_mid_smi_ctrl,
.ioc = IOC_SMI_CHANNEL_SELECT
};
val = (channel == caribou_fpga_smi_channel_0) ? 0x0 : 0x1;
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), &val);
}
//--------------------------------------------------------------
int caribou_fpga_set_smi_ctrl_data_direction (caribou_fpga_st* dev, uint8_t dir)
{
CARIBOU_FPGA_CHECK_DEV(dev,"caribou_fpga_set_smi_ctrl_data_direction");
caribou_fpga_opcode_st oc =
{
.rw = caribou_fpga_rw_write,
.mid = caribou_fpga_mid_smi_ctrl,
.ioc = IOC_SMI_CTRL_DIR_SELECT
};
return caribou_fpga_spi_transfer (dev, (uint8_t*)(&oc), (uint8_t*)&dir);
}

Wyświetl plik

@ -1,181 +0,0 @@
#ifndef __CARIBOU_FPGA_H__
#define __CARIBOU_FPGA_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdint.h>
#include "io_utils/io_utils.h"
#include "io_utils/io_utils_spi.h"
#include "caribou_programming/caribou_prog.h"
/**
* @brief Tha manufacturer code - used to verify the FPGA's programming
*/
#define CARIBOU_SDR_MANU_CODE 0x1
#pragma pack(1)
/**
* @brief Firmware versions and inner modules information
*/
typedef struct
{
uint8_t sys_ver;
uint8_t sys_manu_id;
uint8_t sys_ctrl_mod_ver;
uint8_t io_ctrl_mod_ver;
uint8_t smi_ctrl_mod_ver;
} caribou_fpga_versions_st;
/**
* @brief Firmware interface generic error codes
*/
typedef enum
{
caribou_fpga_ec_okay = 0x00,
caribou_fpga_ec_write_attempt_to_readonly = 0x01,
} caribou_fpga_ec_en; // error codes
/**
* @brief RF front end modes of operations
*/
typedef enum
{
caribou_fpga_io_ctrl_rfm_low_power = 0,
caribou_fpga_io_ctrl_rfm_bypass = 1,
caribou_fpga_io_ctrl_rfm_rx_lowpass = 2,
caribou_fpga_io_ctrl_rfm_rx_hipass = 3,
caribou_fpga_io_ctrl_rfm_tx_lowpass = 4,
caribou_fpga_io_ctrl_rfm_tx_hipass = 5,
} caribou_fpga_io_ctrl_rfm_en;
/**
* @brief FPGA status - either not programmed or programmed with
* a valid firmware
*/
typedef enum
{
caribou_fpga_status_not_programmed = 0,
caribou_fpga_status_operational = 1,
} caribou_fpga_status_en;
/**
* @brief RFFE controlling digital pins specifically controlled
* when in debug mode (read anytime)
*/
typedef struct
{
uint8_t mixer_en : 1; // LSB
uint8_t lna_rx_shdn : 1;
uint8_t lna_tx_shdn : 1;
uint8_t trvc2 : 1;
uint8_t trvc1_b : 1;
uint8_t trvc1 : 1;
uint8_t rx_h_tx_l_b : 1;
uint8_t rx_h_tx_l : 1; // MSB
} caribou_fpga_rf_pin_st;
/**
* @brief SMI fifo status struct
*/
typedef struct
{
uint8_t rx_fifo_empty : 1; // LSB
uint8_t tx_fifo_full : 1;
uint8_t smi_channel: 1;
uint8_t i_smi_test : 1;
uint8_t reserved : 4; // MSB
} caribou_fpga_smi_fifo_status_st;
/**
* @brief SMI channel select
*/
typedef enum
{
caribou_fpga_smi_channel_0 = 0,
caribou_fpga_smi_channel_1 = 1,
} caribou_fpga_smi_channel_en;
#pragma pack()
/**
* @brief Firmware control and programming device context
*/
typedef struct
{
// pinout
int reset_pin;
int soft_reset_pin;
int cs_pin;
// spi device
int spi_dev;
int spi_channel;
// programming
caribou_prog_st prog_dev;
caribou_fpga_status_en status;
caribou_fpga_versions_st versions;
// internal controls
io_utils_spi_st* io_spi;
int io_spi_handle;
int initialized;
} caribou_fpga_st;
/**
* @brief initialize FPGA device driver
*
* @param dev pointer to device context - should be preinitialized with pinout and spi info
* @param io_spi spi device
* @return int success (0) / failure (-1)
*/
int caribou_fpga_init(caribou_fpga_st* dev, io_utils_spi_st* io_spi);
int caribou_fpga_close(caribou_fpga_st* dev);
int caribou_fpga_soft_reset(caribou_fpga_st* dev);
int caribou_fpga_hard_reset(caribou_fpga_st* dev);
int caribou_fpga_hard_reset_keep(caribou_fpga_st* dev, bool reset);
// programming
int caribou_fpga_get_status(caribou_fpga_st* dev, caribou_fpga_status_en *stat);
int caribou_fpga_program_to_fpga(caribou_fpga_st* dev, unsigned char *buffer, size_t len, bool force_prog);
int caribou_fpga_program_to_fpga_from_file(caribou_fpga_st* dev, char *filename, bool force_prog);
// System Controller
int caribou_fpga_get_versions (caribou_fpga_st* dev, caribou_fpga_versions_st *vers);
void caribou_fpga_print_versions (caribou_fpga_st* dev);
int caribou_fpga_get_errors (caribou_fpga_st* dev, uint8_t *err_map);
char* caribou_fpga_get_mode_name (caribou_fpga_io_ctrl_rfm_en mode);
int caribou_fpga_set_debug_modes (caribou_fpga_st* dev, bool dbg_fifo_push, bool dbg_fifo_pull, bool dbg_smi);
int caribou_fpga_set_sys_ctrl_tx_sample_gap (caribou_fpga_st* dev, uint8_t gap);
int caribou_fpga_get_sys_ctrl_tx_sample_gap (caribou_fpga_st* dev, uint8_t *gap);
// I/O Controller
int caribou_fpga_set_io_ctrl_mode (caribou_fpga_st* dev, uint8_t debug_mode, caribou_fpga_io_ctrl_rfm_en rfm);
int caribou_fpga_get_io_ctrl_mode (caribou_fpga_st* dev, uint8_t *debug_mode, caribou_fpga_io_ctrl_rfm_en *rfm);
int caribou_fpga_set_io_ctrl_dig (caribou_fpga_st* dev, int led0, int led1);
int caribou_fpga_get_io_ctrl_dig (caribou_fpga_st* dev, int *led0, int *led1, int *btn, int *cfg);
int caribou_fpga_set_io_ctrl_pmod_dir (caribou_fpga_st* dev, uint8_t dir);
int caribou_fpga_get_io_ctrl_pmod_dir (caribou_fpga_st* dev, uint8_t *dir);
int caribou_fpga_set_io_ctrl_pmod_val (caribou_fpga_st* dev, uint8_t val);
int caribou_fpga_get_io_ctrl_pmod_val (caribou_fpga_st* dev, uint8_t *val);
int caribou_fpga_set_io_ctrl_rf_state (caribou_fpga_st* dev, caribou_fpga_rf_pin_st *pins);
int caribou_fpga_get_io_ctrl_rf_state (caribou_fpga_st* dev, caribou_fpga_rf_pin_st *pins);
// SMI Controller
int caribou_fpga_get_smi_ctrl_fifo_status (caribou_fpga_st* dev, caribou_fpga_smi_fifo_status_st *status);
int caribou_fpga_set_smi_channel (caribou_fpga_st* dev, caribou_fpga_smi_channel_en channel);
int caribou_fpga_set_smi_ctrl_data_direction (caribou_fpga_st* dev, uint8_t dir);
#ifdef __cplusplus
}
#endif
#endif // __CARIBOU_FPGA_H__

Wyświetl plik

@ -1,220 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include "caribou_fpga.h"
#define CARIBOULITE_MOSI 20
#define CARIBOULITE_SCK 21
#define CARIBOULITE_MISO 19
#define FPGA_RESET 26
#define FPGA_CS 18
#define CARIBOULITE_SPI_DEV 1
#define CARIBOULITE_FPGA_SPI_CHANNEL 0
io_utils_spi_st io_spi_dev =
{
.miso = CARIBOULITE_MISO,
.mosi = CARIBOULITE_MOSI,
.sck = CARIBOULITE_SCK,
};
caribou_fpga_st dev =
{
.reset_pin = FPGA_RESET,
.cs_pin = FPGA_CS,
.spi_dev = CARIBOULITE_SPI_DEV,
.spi_channel = CARIBOULITE_FPGA_SPI_CHANNEL,
};
int main ()
{
printf("Hello from CaribouFPGA!\n");
// Init GPIOs and set FPGA on reset
io_utils_setup(NULL);
// Init spi
io_utils_spi_init(&io_spi_dev);
// init fpga comm
caribou_fpga_init(&dev, &io_spi_dev);
// get versions
caribou_fpga_versions_st versions = {0};
caribou_fpga_get_versions (&dev, &versions);
printf("VERSIONS: sys: 0x%02X, manu: 0x%02X, sys_ctrl: 0x%02X, io_ctrl: 0x%02X, smi_ctrl: 0x%02X\n",
versions.sys_ver,
versions.sys_manu_id,
versions.sys_ctrl_mod_ver,
versions.io_ctrl_mod_ver,
versions.smi_ctrl_mod_ver);
// get errors
uint8_t err_map = 0;
caribou_fpga_get_errors (&dev, &err_map);
printf("ERRORS: 0x%02X\n -- Press Enter to Soft-Reset --\n", err_map);
// soft reset
getchar();
caribou_fpga_soft_reset(&dev);
// io control mode
uint8_t debug_mode = 0;
caribou_fpga_io_ctrl_rfm_en rfmode = 0;
caribou_fpga_get_io_ctrl_mode (&dev, &debug_mode, &rfmode);
printf("IO_CTRL MODE: debug = %d, rfm = %d\n", debug_mode, rfmode);
// io_ctrl_dig
int led0 = 0;
int led1 = 0;
int btn = 0;
int cfg = 0;
caribou_fpga_get_io_ctrl_dig (&dev, &led0, &led1, &btn, &cfg);
printf("IO_CTRL: led0: %d, led1: %d, btn: %d, cfg: 0x%02X\n", led0, led1, btn, cfg);
// pmod dir
uint8_t dir = 0;
caribou_fpga_get_io_ctrl_pmod_dir (&dev, &dir);
printf("PMOD_DIR: dir = 0x%02X\n", dir);
// pmod val
uint8_t val = 0;
caribou_fpga_get_io_ctrl_pmod_val (&dev, &val);
printf("PMOD_VAL: val = 0x%02X\n", val);
// rf state
caribou_fpga_rf_pin_st pins = {0};
uint32_t *pins_uint = (uint32_t*)&pins;
caribou_fpga_get_io_ctrl_rf_state (&dev, &pins);
printf("RF_PIN_STATE: val = 0x%02X\n", *(pins_uint));
// smi fifo status
caribou_fpga_smi_fifo_status_st fifo_stat = {0};
caribou_fpga_get_smi_ctrl_fifo_status (&dev, &fifo_stat);
printf("SMI_FIFO_STAT: rx_09_empty = %d, rx_09_full = %d, rx_24_empty = %d, rx_24_full = %d, res = 0x%02X\n",
fifo_stat.rx_fifo_09_empty,
fifo_stat.rx_fifo_09_full,
fifo_stat.rx_fifo_24_empty,
fifo_stat.rx_fifo_24_full,
fifo_stat.res );
// setting RF states RFM
printf("MODE = caribou_fpga_io_ctrl_rfm_low_power\npress enter\n");
caribou_fpga_set_io_ctrl_mode (&dev, 0, caribou_fpga_io_ctrl_rfm_low_power);
caribou_fpga_get_io_ctrl_mode (&dev, &debug_mode, &rfmode);
printf("IO_CTRL MODE: debug = %d, rfm = %d (should be %d)\n", debug_mode, rfmode, caribou_fpga_io_ctrl_rfm_low_power);
caribou_fpga_get_io_ctrl_rf_state (&dev, &pins);
printf("RF_PIN_STATE: val = 0x%02X\n", *(pins_uint));
getchar();
printf("MODE = caribou_fpga_io_ctrl_rfm_bypass\npress enter\n");
caribou_fpga_set_io_ctrl_mode (&dev, 0, caribou_fpga_io_ctrl_rfm_bypass);
caribou_fpga_get_io_ctrl_mode (&dev, &debug_mode, &rfmode);
printf("IO_CTRL MODE: debug = %d, rfm = %d (should be %d)\n", debug_mode, rfmode, caribou_fpga_io_ctrl_rfm_bypass);
caribou_fpga_get_io_ctrl_rf_state (&dev, &pins);
printf("RF_PIN_STATE: val = 0x%02X\n", *(pins_uint));
getchar();
printf("MODE = caribou_fpga_io_ctrl_rfm_rx_lowpass\npress enter\n");
caribou_fpga_set_io_ctrl_mode (&dev, 0, caribou_fpga_io_ctrl_rfm_rx_lowpass);
caribou_fpga_get_io_ctrl_mode (&dev, &debug_mode, &rfmode);
printf("IO_CTRL MODE: debug = %d, rfm = %d (should be %d)\n", debug_mode, rfmode, caribou_fpga_io_ctrl_rfm_rx_lowpass);
caribou_fpga_get_io_ctrl_rf_state (&dev, &pins);
printf("RF_PIN_STATE: val = 0x%02X\n", *(pins_uint));
getchar();
printf("MODE = caribou_fpga_io_ctrl_rfm_rx_hipass\npress enter\n");
caribou_fpga_set_io_ctrl_mode (&dev, 0, caribou_fpga_io_ctrl_rfm_rx_hipass);
caribou_fpga_get_io_ctrl_mode (&dev, &debug_mode, &rfmode);
printf("IO_CTRL MODE: debug = %d, rfm = %d (should be %d)\n", debug_mode, rfmode, caribou_fpga_io_ctrl_rfm_rx_hipass);
caribou_fpga_get_io_ctrl_rf_state (&dev, &pins);
printf("RF_PIN_STATE: val = 0x%02X\n", *(pins_uint));
getchar();
printf("MODE = caribou_fpga_io_ctrl_rfm_tx_lowpass\npress enter\n");
caribou_fpga_set_io_ctrl_mode (&dev, 0, caribou_fpga_io_ctrl_rfm_tx_lowpass);
caribou_fpga_get_io_ctrl_mode (&dev, &debug_mode, &rfmode);
printf("IO_CTRL MODE: debug = %d, rfm = %d (should be %d)\n", debug_mode, rfmode, caribou_fpga_io_ctrl_rfm_tx_lowpass);
caribou_fpga_get_io_ctrl_rf_state (&dev, &pins);
printf("RF_PIN_STATE: val = 0x%02X\n", *(pins_uint));
getchar();
printf("MODE = caribou_fpga_io_ctrl_rfm_tx_hipass\npress enter\n");
caribou_fpga_set_io_ctrl_mode (&dev, 0, caribou_fpga_io_ctrl_rfm_tx_hipass);
caribou_fpga_get_io_ctrl_mode (&dev, &debug_mode, &rfmode);
printf("IO_CTRL MODE: debug = %d, rfm = %d (should be %d)\n", debug_mode, rfmode, caribou_fpga_io_ctrl_rfm_tx_hipass);
caribou_fpga_get_io_ctrl_rf_state (&dev, &pins);
printf("RF_PIN_STATE: val = 0x%02X\n", *(pins_uint));
getchar();
caribou_fpga_set_io_ctrl_mode (&dev, 0, caribou_fpga_io_ctrl_rfm_low_power);
caribou_fpga_get_io_ctrl_mode (&dev, &debug_mode, &rfmode);
printf("IO_CTRL MODE: debug = %d, rfm = %d (should be %d)\n", debug_mode, rfmode, caribou_fpga_io_ctrl_rfm_low_power);
caribou_fpga_get_io_ctrl_rf_state (&dev, &pins);
printf("RF_PIN_STATE: val = 0x%02X\n", *(pins_uint));
// read out stuff
/*caribou_fpga_versions_st vers = {0};
uint8_t err_map = 0;
int error_count = 0;
int error_count1 = 0;
for (int i = 0; i < 1000; i++)
{
caribou_fpga_get_versions (&dev, &vers);
if (vers.sys_ver != 0x01 || vers.sys_manu_id != 0x01 ||
vers.sys_ctrl_mod_ver != 0x01 || vers.io_ctrl_mod_ver != 0x01 ||
vers.smi_ctrl_mod_ver != 0x01)
error_count ++;
uint8_t val = 0;
caribou_fpga_set_io_ctrl_pmod_val (&dev, i&0xFF);
caribou_fpga_get_io_ctrl_pmod_val (&dev, &val);
if (val != (i&0xFF))
{
error_count1 ++ ;
}
//printf("Versions: %d, %d, %d, %d, %d\n", vers.sys_ver, vers.sys_manu_id,
// vers.sys_ctrl_mod_ver, vers.io_ctrl_mod_ver, vers.smi_ctrl_mod_ver);
}
printf("Errors # = %d, error_count1 = %d\n", error_count, error_count1);
//caribou_fpga_get_errors (&dev, &err_map);
//printf("Received Error map: %02X\n", err_map);
// settings
for (int i = 0; i < 5; i++)
{
caribou_fpga_set_io_ctrl_dig (&dev, 1, 1, 1);
caribou_fpga_set_io_ctrl_pmod_val (&dev, 0xAA);
io_utils_usleep(500000);
caribou_fpga_set_io_ctrl_dig (&dev, 0, 0, 0);
caribou_fpga_set_io_ctrl_pmod_val (&dev, 0x55);
io_utils_usleep(500000);
}
caribou_fpga_set_io_ctrl_dig (&dev, 1, 0, 1);
//caribou_fpga_set_io_ctrl_pmod_dir (&dev, 0x55);
caribou_fpga_set_io_ctrl_pmod_val (&dev, 0xAA);
uint8_t val = 0;
caribou_fpga_get_io_ctrl_pmod_val (&dev, &val);
printf("PMOD VAL: %02X\n", val);*/
// close everything
caribou_fpga_close(&dev);
io_utils_spi_close(&io_spi_dev);
io_utils_cleanup();
return 0;
}

Wyświetl plik

@ -1,2 +0,0 @@
# build directories
build

Wyświetl plik

@ -1,21 +0,0 @@
cmake_minimum_required(VERSION 3.15)
project(cariboulite)
set(CMAKE_BUILD_TYPE Release)
#Bring the headers, such as Student.h into the project
set(SUPER_DIR ${PROJECT_SOURCE_DIR}/..)
include_directories(/.)
include_directories(${SUPER_DIR})
#However, the file(GLOB...) allows for wildcard additions:
set(SOURCES_LIB caribou_prog.c)
#add_compile_options(-Wall -Wextra -pedantic -Werror)
add_compile_options(-Wall -Wextra -Wno-missing-braces)
#Generate the static library from the sources
add_library(caribou_prog STATIC ${SOURCES_LIB})
target_include_directories(caribou_prog PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
#Set the location for library installation -- i.e., /usr/lib in this case
# not really necessary in this example. Use "sudo make install" to apply
install(TARGETS caribou_prog DESTINATION /usr/lib)

Wyświetl plik

@ -1,5 +0,0 @@
# Overview
This Lattice ICE40 programming and management library was originally written by Eric Brombaugh (https://github.com/emeb) and used in https://github.com/emeb/icehat ("...RPi hat which comprises a Lattice iCE40 Ultra FPGA type ice5LP4K-SG48...").
# License
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.

Wyświetl plik

@ -1,406 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "CARIBOU_PROG"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "zf_log/zf_log.h"
#include "caribou_prog.h"
#define LATTICE_ICE40_BUFSIZE 512
#define LATTICE_ICE40_TO_COUNT 200
//---------------------------------------------------------------------------
/**
* @brief check whether the fpga is currently in a "programmed" mode
*
* @param dev programmer context
* @return int success(0), error(-1)
*/
static int caribou_prog_check_if_programmed(caribou_prog_st* dev)
{
if (dev == NULL)
{
ZF_LOGE("device pointer NULL");
return -1;
}
if (!dev->initialized)
{
ZF_LOGE("device not initialized");
return -1;
}
return io_utils_read_gpio(dev->cdone_pin);
}
//---------------------------------------------------------------------------
/**
* @brief initialize programmer context
*
* @param dev programmer device context
* @param io_spi spi device wrapper
* @return int success(0) / error(-1)
*/
int caribou_prog_init(caribou_prog_st *dev, io_utils_spi_st* io_spi)
{
if (dev == NULL)
{
ZF_LOGE("device pointer NULL");
return -1;
}
if (dev->initialized)
{
ZF_LOGE("device already initialized");
return 0;
}
dev->io_spi = io_spi;
// Init pin directions
io_utils_setup_gpio(dev->cdone_pin, io_utils_dir_input, io_utils_pull_up);
io_utils_setup_gpio(dev->cs_pin, io_utils_dir_output, io_utils_pull_up);
io_utils_setup_gpio(dev->reset_pin, io_utils_dir_output, io_utils_pull_up);
dev->io_spi_handle = io_utils_spi_add_chip( dev->io_spi,
dev->cs_pin,
2000000,
0,
0,
io_utils_spi_chip_ice40_prog, NULL);
dev->initialized = 1;
// check if the FPGA is already configures
if (caribou_prog_check_if_programmed(dev) == 1)
{
ZF_LOGD("FPGA is already configured and running");
}
ZF_LOGD("device init completed");
return 0;
}
//---------------------------------------------------------------------------
/**
* @brief release the fpga programmer context
*
* @param dev device context
* @return int success(0) / error(-1)
*/
int caribou_prog_release(caribou_prog_st *dev)
{
if (dev == NULL)
{
ZF_LOGE("device pointer NULL");
return -1;
}
if (!dev->initialized)
{
ZF_LOGE("device not initialized");
return 0;
}
// Release the SPI device
io_utils_spi_remove_chip(dev->io_spi, dev->io_spi_handle);
// Release the GPIO functions
io_utils_setup_gpio(dev->cdone_pin, io_utils_dir_input, io_utils_pull_up);
io_utils_setup_gpio(dev->cs_pin, io_utils_dir_input, io_utils_pull_up);
io_utils_setup_gpio(dev->reset_pin, io_utils_dir_input, io_utils_pull_up);
dev->initialized = 0;
ZF_LOGI("device release completed");
return 0;
}
//---------------------------------------------------------------------------
/**
* @brief performs preparation steps towards bitstream programming
*
* @param dev device context
* @return int success(0) / error(-1)
*/
static int caribou_prog_configure_prepare(caribou_prog_st *dev)
{
long ct;
uint8_t byte = 0xFF;
uint8_t rxbyte = 0;
// set SS low for spi config
io_utils_write_gpio_with_wait(dev->cs_pin, 0, 200);
// pulse RST low min 200 us ns
io_utils_write_gpio_with_wait(dev->reset_pin, 0, 200);
io_utils_usleep(200);
// Wait for DONE low
ZF_LOGD("RESET low, Waiting for CDONE low");
ct = LATTICE_ICE40_TO_COUNT;
while(io_utils_read_gpio(dev->cdone_pin)==1 && ct--)
{
asm volatile ("nop");
}
if (!ct)
{
ZF_LOGE("CDONE didn't fall during RESET='0'");
return -1;
}
io_utils_write_gpio_with_wait(dev->reset_pin, 1, 200);
io_utils_usleep(1200);
// Send 8 dummy clocks with SS high
io_utils_write_gpio_with_wait(dev->cs_pin, 1, 200);
io_utils_spi_transmit(dev->io_spi, dev->io_spi_handle, &byte, &rxbyte, 1, io_utils_spi_write);
return 0;
}
//---------------------------------------------------------------------------
/**
* @brief performs finalization steps after bitstream programming
*
* @param dev device context
* @return int success(0) / error(-1)
*/
static int caribou_prog_configure_finish(caribou_prog_st *dev)
{
int ct = 0;
uint8_t byte = 0xFF;
uint8_t rxbyte = 0;
unsigned char dummybuf[10] = {0};
// Transmit at least 49 clock cycles of clock
io_utils_spi_transmit(dev->io_spi, dev->io_spi_handle,
dummybuf,
dummybuf,
8,
io_utils_spi_write);
/* send dummy data while waiting for DONE */
ZF_LOGD("sending dummy clocks, waiting for CDONE to rise (or fail)");
ct = LATTICE_ICE40_TO_COUNT;
int count = 0;
while((caribou_prog_check_if_programmed(dev)==0 && ct--) || count++ < 4)
{
io_utils_spi_transmit(dev->io_spi, dev->io_spi_handle,
&byte, &rxbyte, 1, io_utils_spi_write);
}
if(ct)
{
ZF_LOGD("%d dummy clocks sent", (LATTICE_ICE40_TO_COUNT-ct)*8);
}
else
{
ZF_LOGW("timeout waiting for CDONE");
}
/* return status */
if (caribou_prog_check_if_programmed(dev)==0)
{
ZF_LOGE("config failed - CDONE not high");
return -1;
}
return 0;
}
//---------------------------------------------------------------------------
/**
* @brief starts programming sequence from a memory buffer
*
* @param dev device context
* @param dest the destination of the bitstream
* @param buffer bitstream buffer pointer
* @param buffer_size bitstream buffer length in bytes
* @return int success(0), error (-1)
*/
int caribou_prog_configure_from_buffer( caribou_prog_st *dev,
uint8_t *buffer,
uint32_t buffer_size)
{
int ct = 0;
int progress = 0;
if (dev == NULL)
{
ZF_LOGE("device pointer NULL");
return -1;
}
if (!dev->initialized)
{
ZF_LOGE("device not initialized");
return -1;
}
// CONFIGURATION PROLOG
// --------------------
if (caribou_prog_configure_prepare( dev ) != 0)
{
ZF_LOGE("Preparation for bitstream sending to fpga failed");
return -1;
}
// CONFIGURATION
// -------------
// Read file & send bitstream to FPGA via SPI with CS LOW
ZF_LOGI("Sending bitstream of size %d", buffer_size);
ct = 0;
io_utils_write_gpio_with_wait(dev->cs_pin, 0, 200);
while( ct < (int)(buffer_size) )
{
unsigned char dummybuf[LATTICE_ICE40_BUFSIZE];
char* readbuf = (char*)(buffer + ct);
int length = (buffer_size-ct)<LATTICE_ICE40_BUFSIZE ? buffer_size-ct : LATTICE_ICE40_BUFSIZE;
// Send bitstream
io_utils_spi_transmit(dev->io_spi, dev->io_spi_handle,
(unsigned char *)readbuf,
dummybuf,
length,
io_utils_spi_write);
ct += length;
// progress
progress = (ct * 100) / buffer_size;
printf("[%2d%%]\r", progress); fflush(stdout);
}
io_utils_write_gpio_with_wait(dev->cs_pin, 1, 200);
ZF_LOGD("bitstream sent %d bytes", ct);
// CONFIGURATION EPILOGUE
// ----------------------
if (caribou_prog_configure_finish(dev) != 0)
{
ZF_LOGE("Finishing the bitstream sending to fpga failed");
return -1;
}
ZF_LOGI("FPGA programming - Success!\n");
return 0;
}
//---------------------------------------------------------------------------
/**
* @brief starts programming sequence from a binary file
*
* @param dev device context
* @param dest the destination of the bitstream
* @param bitfilename path to the file containing the fpga bitstream
* @return int success(0), error (-1)
*/
int caribou_prog_configure(caribou_prog_st *dev, char *bitfilename)
{
FILE *fd = NULL;
int ct = 0;
int read;
unsigned char dummybuf[LATTICE_ICE40_BUFSIZE];
char readbuf[LATTICE_ICE40_BUFSIZE];
int progress = 0;
long file_length = 0;
if (dev == NULL)
{
ZF_LOGE("device pointer NULL");
return -1;
}
if (!dev->initialized)
{
ZF_LOGE("device not initialized");
return -1;
}
// FILE OPENING
// ------------
if(!(fd = fopen(bitfilename, "r")))
{
ZF_LOGE("open file %s failed", bitfilename);
return -1;
}
else
{
fseek(fd, 0L, SEEK_END);
file_length = ftell(fd);
ZF_LOGI("opened bitstream file %s", bitfilename);
fseek(fd, 0L, SEEK_SET);
}
// CONFIGURATION PROLOG
// --------------------
if (caribou_prog_configure_prepare( dev ) != 0)
{
ZF_LOGE("Preparation for bitstream sending to fpga failed");
return -1;
}
// CONFIGURATION
// -------------
// Read file & send bitstream to FPGA via SPI with CS LOW
ZF_LOGI("Sending bitstream of size %ld", file_length);
ct = 0;
io_utils_write_gpio_with_wait(dev->cs_pin, 0, 200);
while( (read=fread(readbuf, sizeof(char), LATTICE_ICE40_BUFSIZE, fd)) > 0 )
{
// Send bitstream
io_utils_spi_transmit(dev->io_spi, dev->io_spi_handle,
(unsigned char *)readbuf,
dummybuf,
read,
io_utils_spi_write);
ct += read;
// progress
progress = (ct * 100) / file_length;
printf("[%2d%%]\r", progress); fflush(stdout);
}
io_utils_write_gpio_with_wait(dev->cs_pin, 1, 200);
// close file
ZF_LOGI("bitstream sent, closing file - sent %d bytes", ct);
fclose(fd);
// CONFIGURATION EPILOGUE
// ----------------------
if (caribou_prog_configure_finish(dev) != 0)
{
ZF_LOGE("Finishing the bitstream sending to fpga failed");
return -1;
}
ZF_LOGI("FPGA programming - Success!\n");
return 0;
}
//---------------------------------------------------------------------------
int caribou_prog_hard_reset(caribou_prog_st *dev, int level)
{
if (level == 0 || level == -1)
{
ZF_LOGD("Resetting FPGA reset pin to 0");
io_utils_write_gpio_with_wait(dev->reset_pin, 0, 200);
io_utils_usleep(1000);
}
if (level == 1 || level == -1)
{
ZF_LOGD("Setting FPGA reset pin to 1");
io_utils_write_gpio_with_wait(dev->reset_pin, 1, 200);
io_utils_usleep(1000);
}
return 0;
}

Wyświetl plik

@ -1,47 +0,0 @@
#ifndef __CARIBOU_PROG_H__
#define __CARIBOU_PROG_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <linux/types.h>
#include "io_utils/io_utils.h"
#include "io_utils/io_utils_spi.h"
/**
* @brief caribou-sdr programmer context
*/
typedef struct
{
int cs_pin;
int cdone_pin;
int reset_pin;
int verbose;
io_utils_spi_st* io_spi;
int io_spi_handle;
int initialized;
} caribou_prog_st;
int caribou_prog_init(caribou_prog_st *dev, io_utils_spi_st* io_spi);
int caribou_prog_release(caribou_prog_st *dev);
int caribou_prog_configure(caribou_prog_st *dev, char *bitfilename);
int caribou_prog_configure_from_buffer( caribou_prog_st *dev,
uint8_t *buffer,
uint32_t buffer_size);
/*
* Hard reset pin toggling function
Level: if -1 => a full reset (1=>0=>1) cycle is performed
if 0 / 1 => the pin is reset or set accordingly
*/
int caribou_prog_hard_reset(caribou_prog_st *dev, int level);
#ifdef __cplusplus
}
#endif
#endif // __CARIBOU_PROG_H__

Wyświetl plik

@ -1,2 +0,0 @@
# build directories
build

Wyświetl plik

@ -1,23 +0,0 @@
cmake_minimum_required(VERSION 3.15)
project(cariboulite)
set(CMAKE_BUILD_TYPE Release)
# Bring the headers
#add_subdirectory(kernel "${CMAKE_CURRENT_BINARY_DIR}/kernel_build")
set(SUPER_DIR ${PROJECT_SOURCE_DIR}/..)
include_directories(/.)
include_directories(${SUPER_DIR})
# allows for wildcard additions:
set(SOURCES_LIB caribou_smi.c smi_utils.c caribou_smi_modules.c)
set(SOURCES ${SOURCES_LIB} test_caribou_smi.c)
set(EXTERN_LIBS ${SUPER_DIR}/io_utils/build/libio_utils.a ${SUPER_DIR}/zf_log/build/libzf_log.a -lpthread)
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-missing-braces -Wno-unused-function -O3)
# Generate the static library from the sources
add_library(caribou_smi STATIC ${SOURCES_LIB})
#add_dependencies(caribou_smi smi_modules)
#add_executable(test_caribou_smi ${SOURCES})
#target_link_libraries(test_caribou_smi ${EXTERN_LIBS} m rt pthread)

Wyświetl plik

@ -1,77 +0,0 @@
# Caribou-SMI API Driver
This directory contains a user-mode interface code with the `bcm2835_smi` kernel module.
To start working with the interface, some kernel modules need to be probed first.
By default, CaribouLite boards are pre-programmed to automatically probe the SMI modules on startup. Each CaribouLite contains an EEPROM device that in programmed during production with the updated device tree overlay (for more info [see here](../../../devicetrees/README.md)) file that loads on startup. This device tree "requests" loading the SMI associated kernel modules on startup. So if you have your CaribouLite board mounted on the 40-pin header, the module probing is not necessary.
To check whether these modules are probed, follow the next command in your Raspberry Pi terminal:
```
lsmod | grep smi
```
you should be seeing the following output:
```
bcm2835_smi_dev 16384 0
bcm2835_smi 20480 1 bcm2835_smi_dev
```
If you do not see these modules, please check:
1. The CaribouLite is properly mounted and powered.
2. The CAribouLite is properly flashed - follow [this link](../../../../docs/flashing/README.md)
For detailed hardware-related information on the SMI interface, please click [here](../../../../docs/smi/README.md)
# The API
## Initializing and closing the SMI instance
**Opening** the device and configuring the error-callback-function to be triggered once an error ocurred:
```
int caribou_smi_init(caribou_smi_st* dev,
caribou_smi_error_callback error_cb,
void* context);
```
**Closing** the device:
```
int caribou_smi_close (caribou_smi_st* dev);
```
## Reading and writing into the device
**Reading** into a buffer with timeout. If the SMI connected device (in this case, CaribouLite) doesn't have enough data to send, this function will wait till the timeout elapses. For non-blocking operation, please set `timeout = 0`
```
int caribou_smi_timeout_read(caribou_smi_st* dev,
caribou_smi_address_en source,
char* buffer,
int size_of_buf,
int timeout_num_millisec);
```
```
writing - TBD
```
## Stream operations
In most cases, working with file read/write synchronously is not the right choice. If we want an asynchronous operation with events and callbacks, we should setup a stream as follows:
```
int caribou_smi_setup_stream(caribou_smi_st* dev,
caribou_smi_stream_type_en type,
caribou_smi_channel_en channel,
int batch_length, int num_buffers,
caribou_smi_data_callback cb,
void* serviced_context);
```
`batch_length` - is the length of a single buffer to serve (in bytes)
`num_buffers` - is the number of batch buffers to allocate - for fluent buffer swapping
`cb` - data callback function that is triggered every time a buffer is ready to be served.
`serviced_context` - the data "requester" that is being serviced by the I/Q data. In most cases that is a higher layered driver / API.
The returned integer is the stream ID used for further operations.
Notes: Once the stream is created it is operational **but paused!** to activate it use the following function (on the specific stream ID). This function is used also for pausing the stream (run = 0).
```
int caribou_smi_run_pause_stream (caribou_smi_st* dev, int id, int run);
```
Gracefully disposing the stream is done using the "destroy" function
```
int caribou_smi_destroy_stream(caribou_smi_st* dev, int id);
```

Wyświetl plik

@ -1,773 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "CARIBOU_SMI"
#include "zf_log/zf_log.h"
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sched.h>
#include <pthread.h>
#include <time.h>
#include <errno.h>
#include "caribou_smi.h"
#include "smi_utils.h"
#include "io_utils/io_utils.h"
//=========================================================================
int caribou_smi_set_driver_streaming_state(caribou_smi_st* dev, smi_stream_state_en state)
{
int ret = ioctl(dev->filedesc, SMI_STREAM_IOC_SET_STREAM_STATUS, state);
if (ret != 0)
{
ZF_LOGE("failed setting smi stream state (%d)", state);
return -1;
}
dev->state = state;
return 0;
}
//=========================================================================
smi_stream_state_en caribou_smi_get_driver_streaming_state(caribou_smi_st* dev)
{
return dev->state;
}
//=========================================================================
static void caribou_smi_print_smi_settings(caribou_smi_st* dev, struct smi_settings *settings)
{
printf("SMI SETTINGS:\n");
printf(" width: %d\n", settings->data_width);
printf(" pack: %c\n", settings->pack_data ? 'Y' : 'N');
printf(" read setup: %d, strobe: %d, hold: %d, pace: %d\n", settings->read_setup_time, settings->read_strobe_time, settings->read_hold_time, settings->read_pace_time);
printf(" write setup: %d, strobe: %d, hold: %d, pace: %d\n", settings->write_setup_time, settings->write_strobe_time, settings->write_hold_time, settings->write_pace_time);
printf(" dma enable: %c, passthru enable: %c\n", settings->dma_enable ? 'Y':'N', settings->dma_passthrough_enable ? 'Y':'N');
printf(" dma threshold read: %d, write: %d\n", settings->dma_read_thresh, settings->dma_write_thresh);
printf(" dma panic threshold read: %d, write: %d\n", settings->dma_panic_read_thresh, settings->dma_panic_write_thresh);
printf(" native kernel chunk size: %ld bytes\n", dev->native_batch_len);
}
//=========================================================================
static int caribou_smi_get_smi_settings(caribou_smi_st *dev, struct smi_settings *settings, bool print)
{
int ret = 0;
ret = ioctl(dev->filedesc, BCM2835_SMI_IOC_GET_SETTINGS, settings);
if (ret != 0)
{
ZF_LOGE("failed reading ioctl from smi fd (settings)");
return -1;
}
ret = ioctl(dev->filedesc, SMI_STREAM_IOC_GET_NATIVE_BUF_SIZE, &dev->native_batch_len);
if (ret != 0)
{
ZF_LOGE("failed reading native batch length, setting the default - this error is not fatal but we have wrong kernel drivers");
dev->native_batch_len = (1024)*(1024)/2;
}
//printf("DEBUG: native batch len: %lu\n", dev->native_batch_len);
if (print)
{
caribou_smi_print_smi_settings(dev, settings);
}
return ret;
}
//=========================================================================
static int caribou_smi_setup_settings (caribou_smi_st* dev, struct smi_settings *settings, bool print)
{
settings->read_setup_time = 0;
settings->read_strobe_time = 5;
settings->read_hold_time = 0;
settings->read_pace_time = 0;
settings->write_setup_time = 0;
settings->write_strobe_time = 5;
settings->write_hold_time = 0;
settings->write_pace_time = 0;
// 8 bit on each transmission (4 TRX per sample)
settings->data_width = SMI_WIDTH_8BIT;
// Enable DMA
settings->dma_enable = 1;
// Whether or not to pack multiple SMI transfers into a single 32 bit FIFO word
settings->pack_data = 1;
// External DREQs enabled
settings->dma_passthrough_enable = 1;
// RX DREQ Threshold Level.
// A RX DREQ will be generated when the RX FIFO exceeds this threshold level.
// This will instruct an external AXI RX DMA to read the RX FIFO.
// If the DMA is set to perform burst reads, the threshold must ensure that there is
// sufficient data in the FIFO to satisfy the burst
// Instruction: Lower is faster response
settings->dma_read_thresh = 1;
// TX DREQ Threshold Level.
// A TX DREQ will be generated when the TX FIFO drops below this threshold level.
// This will instruct an external AXI TX DMA to write more data to the TX FIFO.
// Instruction: Higher is faster response
settings->dma_write_thresh = 254;
// RX Panic Threshold level.
// A RX Panic will be generated when the RX FIFO exceeds this threshold level.
// This will instruct the AXI RX DMA to increase the priority of its bus requests.
// Instruction: Lower is more aggressive
settings->dma_panic_read_thresh = 16;
// TX Panic threshold level.
// A TX Panic will be generated when the TX FIFO drops below this threshold level.
// This will instruct the AXI TX DMA to increase the priority of its bus requests.
// Instruction: Higher is more aggresive
settings->dma_panic_write_thresh = 224;
if (print)
{
caribou_smi_print_smi_settings(dev, settings);
}
if (ioctl(dev->filedesc, BCM2835_SMI_IOC_WRITE_SETTINGS, settings) != 0)
{
ZF_LOGE("failed writing ioctl to the smi fd (settings)");
return -1;
}
// set the address line parameters
int address_dir_offset = 2;
if (ioctl(dev->filedesc, SMI_STREAM_IOC_SET_ADDR_DIR_OFFSET, address_dir_offset) != 0)
{
ZF_LOGE("failed writing ioctl to the smi fd (address_dir_offset)");
return -1;
}
// set the address line parameters
int address_channel_offset = 3;
if (ioctl(dev->filedesc, SMI_STREAM_IOC_SET_ADDR_CH_OFFSET, address_channel_offset) != 0)
{
ZF_LOGE("failed writing ioctl to the smi fd (address_channel_offset)");
return -1;
}
return 0;
}
//=========================================================================
static void caribou_smi_anayze_smi_debug(caribou_smi_st* dev, uint8_t *data, size_t len)
{
uint32_t error_counter_current = 0;
int first_error = -1;
uint32_t *values = (uint32_t*)data;
//smi_utils_dump_hex(buffer, 12);
if (dev->debug_mode == caribou_smi_lfsr)
{
for (size_t i = 0; i < len; i++)
{
if (data[i] != smi_utils_lfsr(dev->debug_data.last_correct_byte) || data[i] == 0)
{
if (first_error == -1) first_error = i;
dev->debug_data.error_accum_counter ++;
error_counter_current ++;
}
dev->debug_data.last_correct_byte = data[i];
}
}
else if (dev->debug_mode == caribou_smi_push || dev->debug_mode == caribou_smi_pull)
{
for (size_t i = 0; i < len / 4; i++)
{
if (values[i] != CARIBOU_SMI_DEBUG_WORD)
{
if (first_error == -1) first_error = i * 4;
dev->debug_data.error_accum_counter += 4;
error_counter_current += 4;
}
}
}
dev->debug_data.cur_err_cnt = error_counter_current;
dev->debug_data.bitrate = smi_calculate_performance(len, &dev->debug_data.last_time, dev->debug_data.bitrate);
dev->debug_data.error_rate = dev->debug_data.error_rate * 0.9 + (double)(error_counter_current) / (double)(len) * 0.1;
if (dev->debug_data.error_rate < 1e-8)
dev->debug_data.error_rate = 0.0;
}
//=========================================================================
static void caribou_smi_print_debug_stats(caribou_smi_st* dev, uint8_t *buffer, size_t len)
{
static unsigned int count = 0;
count ++;
if (count % 10 == 0)
{
printf("SMI DBG: ErrAccumCnt: %d, LastErrCnt: %d, ErrorRate: %.4g, bitrate: %.2f Mbps\n",
dev->debug_data.error_accum_counter,
dev->debug_data.cur_err_cnt,
dev->debug_data.error_rate,
dev->debug_data.bitrate);
}
//smi_utils_dump_hex(buffer, 16);
}
//=========================================================================
static int caribou_smi_find_buffer_offset(caribou_smi_st* dev, uint8_t *buffer, size_t len)
{
size_t offs = 0;
bool found = false;
if (len <= 4)
{
return 0;
}
if (dev->debug_mode == caribou_smi_none)
{
for (offs = 0; offs<(len-(CARIBOU_SMI_BYTES_PER_SAMPLE*4)); offs++)
{
uint32_t s1 = *((uint32_t*)(&buffer[offs]));
uint32_t s2 = *((uint32_t*)(&buffer[offs+4]));
uint32_t s3 = *((uint32_t*)(&buffer[offs+8]));
uint32_t s4 = *((uint32_t*)(&buffer[offs+12]));
//printf("%d => %08X\n", offs, s);
if ((s1 & 0xC001C000) == 0x80004000 &&
(s2 & 0xC001C000) == 0x80004000 &&
(s3 & 0xC001C000) == 0x80004000 &&
(s4 & 0xC001C000) == 0x80004000)
{
found = true;
break;
}
}
}
else if (dev->debug_mode == caribou_smi_push || dev->debug_mode == caribou_smi_pull)
{
for (offs = 0; offs<(len-CARIBOU_SMI_BYTES_PER_SAMPLE); offs++)
{
uint32_t s = /*__builtin_bswap32*/(*((uint32_t*)(&buffer[offs])));
//printf("%d => %08X, %08X\n", offs, s, caribou_smi_count_bit(s^CARIBOU_SMI_DEBUG_WORD));
if (smi_utils_count_bit(s^CARIBOU_SMI_DEBUG_WORD) < 4)
{
found = true;
break;
}
}
}
else
{
// the lfsr option
return 0;
}
if (found == false)
{
return -1;
}
return (int)offs;
}
//=========================================================================
static int caribou_smi_rx_data_analyze(caribou_smi_st* dev,
caribou_smi_channel_en channel,
uint8_t* data, size_t data_length,
caribou_smi_sample_complex_int16* samples_out,
caribou_smi_sample_meta* meta_offset)
{
int offs = 0;
size_t actual_length = data_length; // in bytes
int size_shortening_samples = 0; // in samples
uint32_t *actual_samples = (uint32_t*)(data);
caribou_smi_sample_complex_int16* cmplx_vec = samples_out;
// find the offset and adjust
offs = caribou_smi_find_buffer_offset(dev, data, data_length);
if (offs > 0)
{
//printf("OFFSET = %d\n", offs);
}
if (offs < 0)
{
return -1;
}
// adjust the lengths accroding to the sample mismatch
// this may be accompanied by a few samples losses (sphoradic OS
// scheduling) thus trying to stitch buffers one to another may
// be not effective. The single sample is interpolated
size_shortening_samples = (offs > 0) ? (offs / CARIBOU_SMI_BYTES_PER_SAMPLE + 1) : 0;
actual_length -= size_shortening_samples * CARIBOU_SMI_BYTES_PER_SAMPLE;
actual_samples = (uint32_t*)(data + offs);
// analyze the data
if (dev->debug_mode != caribou_smi_none)
{
caribou_smi_anayze_smi_debug(dev, (uint8_t*)actual_samples, actual_length);
}
else
{
unsigned int i = 0;
// Print buffer
//smi_utils_dump_bin(buffer, 16);
// Data Structure:
// [31:30] [ 29:17 ] [ 16 ] [ 15:14 ] [ 13:1 ] [ 0 ]
// [ '10'] [ I sample ] [ '0' ] [ '01' ] [ Q sample ] [ 'S' ]
if (channel != caribou_smi_channel_2400)
{ /* S1G */
for (i = 0; i < actual_length / CARIBOU_SMI_BYTES_PER_SAMPLE; i++)
{
uint32_t s = /*__builtin_bswap32*/(actual_samples[i]);
if (meta_offset) meta_offset[i].sync = s & 0x00000001;
if (cmplx_vec)
{
s >>= 1;
cmplx_vec[i].q = s & 0x00001FFF; s >>= 13;
s >>= 3;
cmplx_vec[i].i = s & 0x00001FFF; s >>= 13;
if (cmplx_vec[i].i >= (int16_t)0x1000) cmplx_vec[i].i -= (int16_t)0x2000;
if (cmplx_vec[i].q >= (int16_t)0x1000) cmplx_vec[i].q -= (int16_t)0x2000;
}
}
}
else
{ /* HiF */
for (i = 0; i < actual_length / CARIBOU_SMI_BYTES_PER_SAMPLE; i++)
{
uint32_t s = /*__builtin_bswap32*/(actual_samples[i]);
if (meta_offset) meta_offset[i].sync = s & 0x00000001;
if (cmplx_vec)
{
s >>= 1;
cmplx_vec[i].i = s & 0x00001FFF; s >>= 13;
s >>= 3;
cmplx_vec[i].q = s & 0x00001FFF; s >>= 13;
if (cmplx_vec[i].i >= (int16_t)0x1000) cmplx_vec[i].i -= (int16_t)0x2000;
if (cmplx_vec[i].q >= (int16_t)0x1000) cmplx_vec[i].q -= (int16_t)0x2000;
}
}
}
// last sample interpolation (linear for I and Q or preserve)
if (size_shortening_samples > 0)
{
//cmplx_vec[i].i = 2*cmplx_vec[i-1].i - cmplx_vec[i-2].i;
//cmplx_vec[i].q = 2*cmplx_vec[i-1].q - cmplx_vec[i-2].q;
cmplx_vec[i].i = 110*cmplx_vec[i-1].i/100 - cmplx_vec[i-2].i/10;
cmplx_vec[i].q = 110*cmplx_vec[i-1].q/100 - cmplx_vec[i-2].q/10;
}
}
return offs;
}
//=========================================================================
static int caribou_smi_poll(caribou_smi_st* dev, uint32_t timeout_num_millisec, smi_stream_direction_en dir)
{
int ret = 0;
struct pollfd fds;
fds.fd = dev->filedesc;
if (dir == smi_stream_dir_device_to_smi) fds.events = POLLIN;
else if (dir == smi_stream_dir_smi_to_device) fds.events = POLLOUT;
else return -1;
again:
ret = poll(&fds, 1, timeout_num_millisec);
if (ret == -1)
{
int error = errno;
switch(error)
{
case EFAULT:
ZF_LOGE("fds points outside the process's accessible address space");
break;
case EINTR:
case EAGAIN:
ZF_LOGD("SMI filedesc select error - caught an interrupting signal");
goto again;
break;
case EINVAL:
ZF_LOGE("The nfds value exceeds the RLIMIT_NOFILE value");
break;
case ENOMEM:
ZF_LOGE("Unable to allocate memory for kernel data structures.");
break;
default: break;
};
return -1;
}
else if(ret == 0)
{
return 0;
}
return fds.revents & POLLIN || fds.revents & POLLOUT;
}
//=========================================================================
static int caribou_smi_timeout_write(caribou_smi_st* dev,
uint8_t* buffer,
size_t len,
uint32_t timeout_num_millisec)
{
int res = caribou_smi_poll(dev, timeout_num_millisec, smi_stream_dir_smi_to_device);
if (res < 0)
{
ZF_LOGD("poll error");
return -1;
}
else if (res == 0) // timeout
{
//ZF_LOGD("===> smi write fd timeout");
return 0;
}
return write(dev->filedesc, buffer, len);
}
//=========================================================================
static int caribou_smi_timeout_read(caribou_smi_st* dev,
uint8_t* buffer,
size_t len,
uint32_t timeout_num_millisec)
{
// try reading the file
int ret = read(dev->filedesc, buffer, len);
if (ret <= 0)
{
int res = caribou_smi_poll(dev, timeout_num_millisec, smi_stream_dir_device_to_smi);
if (res < 0)
{
ZF_LOGD("poll error");
return -1;
}
else if (res == 0) // timeout
{
//ZF_LOGD("===> smi read fd timeout");
return 0;
}
return read(dev->filedesc, buffer, len);
}
return ret;
}
//=========================================================================
void caribou_smi_setup_ios(caribou_smi_st* dev)
{
// setup the addresses
io_utils_set_gpio_mode(2, io_utils_alt_1); // addr
io_utils_set_gpio_mode(3, io_utils_alt_1); // addr
// Setup the bus I/Os
// --------------------------------------------
for (int i = 6; i <= 15; i++)
{
io_utils_set_gpio_mode(i, io_utils_alt_1); // 8xData + SWE + SOE
}
io_utils_set_gpio_mode(24, io_utils_alt_1); // rwreq
io_utils_set_gpio_mode(25, io_utils_alt_1); // rwreq
}
//=========================================================================
int caribou_smi_init(caribou_smi_st* dev,
void* context)
{
char smi_file[] = "/dev/smi";
struct smi_settings settings = {0};
dev->read_temp_buffer = NULL;
dev->write_temp_buffer = NULL;
ZF_LOGD("initializing caribou_smi");
// start from a defined state
memset(dev, 0, sizeof(caribou_smi_st));
// checking the loaded modules
// --------------------------------------------
/*if (caribou_smi_check_modules(true) < 0)
{
ZF_LOGE("Problem reloading SMI kernel modules");
return -1;
}*/
// open the smi device file
// --------------------------------------------
int fd = open(smi_file, O_RDWR);
if (fd < 0)
{
ZF_LOGE("couldn't open smi driver file '%s' (%s)", smi_file, strerror(errno));
return -1;
}
dev->filedesc = fd;
// Setup the bus I/Os
// --------------------------------------------
caribou_smi_setup_ios(dev);
// Retrieve the current settings and modify
// --------------------------------------------
if (caribou_smi_get_smi_settings(dev, &settings, false) != 0)
{
caribou_smi_close (dev);
return -1;
}
if (caribou_smi_setup_settings(dev, &settings, false) != 0)
{
caribou_smi_close (dev);
return -1;
}
// Initialize temporary buffers
// we add additional bytes to allow data synchronization corrections
dev->read_temp_buffer = malloc (dev->native_batch_len + 1024);
dev->write_temp_buffer = malloc (dev->native_batch_len + 1024);
if (dev->read_temp_buffer == NULL || dev->write_temp_buffer == NULL)
{
ZF_LOGE("smi temporary buffers allocation failed");
caribou_smi_close (dev);
return -1;
}
memset(&dev->debug_data, 0, sizeof(caribou_smi_debug_data_st));
dev->debug_mode = caribou_smi_none;
dev->invert_iq = false;
dev->sample_rate = CARIBOU_SMI_SAMPLE_RATE;
dev->initialized = 1;
return 0;
}
//=========================================================================
int caribou_smi_close (caribou_smi_st* dev)
{
// release temporary buffers
if (dev->read_temp_buffer) free(dev->read_temp_buffer);
if (dev->write_temp_buffer) free(dev->write_temp_buffer);
// close smi device file
return close (dev->filedesc);
}
//=========================================================================
void caribou_smi_set_sample_rate(caribou_smi_st* dev, uint32_t sample_rate)
{
if (sample_rate < 100000)
{
dev->sample_rate = 100000;
}
else if (sample_rate > CARIBOU_SMI_SAMPLE_RATE)
{
dev->sample_rate = CARIBOU_SMI_SAMPLE_RATE;
}
else
{
dev->sample_rate = sample_rate;
}
}
//=========================================================================
void caribou_smi_set_debug_mode(caribou_smi_st* dev, caribou_smi_debug_mode_en mode)
{
dev->debug_mode = mode;
}
//=========================================================================
void caribou_smi_invert_iq(caribou_smi_st* dev, bool invert)
{
dev->invert_iq = invert;
}
//=========================================================================
static int caribou_smi_calc_read_timeout(uint32_t sample_rate, size_t len)
{
uint32_t to_millisec = (2 * len * 1000) / sample_rate;
if (to_millisec < 1) to_millisec = 1;
return to_millisec;
}
//=========================================================================
int caribou_smi_read(caribou_smi_st* dev, caribou_smi_channel_en channel,
caribou_smi_sample_complex_int16* samples,
caribou_smi_sample_meta* metadata,
size_t length_samples)
{
caribou_smi_sample_complex_int16* sample_offset = samples;
caribou_smi_sample_meta* meta_offset = metadata;
size_t left_to_read = length_samples * CARIBOU_SMI_BYTES_PER_SAMPLE; // in bytes
size_t read_so_far = 0; // in samples
uint32_t to_millisec = caribou_smi_calc_read_timeout(dev->sample_rate, dev->native_batch_len);
while (left_to_read)
{
if (sample_offset) sample_offset = samples + read_so_far;
if (meta_offset) meta_offset = metadata + read_so_far;
// current_read_len in bytes
size_t current_read_len = ((left_to_read > dev->native_batch_len) ? dev->native_batch_len : left_to_read);
to_millisec = caribou_smi_calc_read_timeout(dev->sample_rate, current_read_len);
int ret = caribou_smi_timeout_read(dev, dev->read_temp_buffer, current_read_len, to_millisec);
if (ret < 0)
{
return -1;
}
else if (ret == 0)
{
ZF_LOGD("Reading timed-out");
break;
}
else
{
int data_affset = caribou_smi_rx_data_analyze(dev, channel, dev->read_temp_buffer, ret, sample_offset, meta_offset);
if (data_affset < 0)
{
return -1;
}
// A special functionality for debug modes
if (dev->debug_mode != caribou_smi_none)
{
caribou_smi_print_debug_stats(dev, dev->read_temp_buffer, ret);
return -2;
}
}
read_so_far += ret / CARIBOU_SMI_BYTES_PER_SAMPLE;
left_to_read -= ret;
}
return read_so_far;
}
#define SMI_TX_SAMPLE_SOF (1<<2)
#define SMI_TX_SAMPLE_MODEM_TX_CTRL (1<<1)
#define SMI_TX_SAMPLE_COND_TX_CTRL (1<<0)
//=========================================================================
static void caribou_smi_generate_data(caribou_smi_st* dev, uint8_t* data, size_t data_length, caribou_smi_sample_complex_int16* sample_offset)
{
caribou_smi_sample_complex_int16* cmplx_vec = sample_offset;
uint32_t *samples = (uint32_t*)(data);
for (unsigned int i = 0; i < (data_length / CARIBOU_SMI_BYTES_PER_SAMPLE); i++)
{
int32_t ii = cmplx_vec[i].i;
int32_t qq = cmplx_vec[i].q;
uint32_t s = SMI_TX_SAMPLE_SOF | SMI_TX_SAMPLE_MODEM_TX_CTRL | SMI_TX_SAMPLE_COND_TX_CTRL; s <<= 5;
s |= (ii >> 8) & 0x1F; s <<= 8;
s |= (ii >> 1) & 0x7F; s <<= 2;
s |= (ii & 0x1); s <<= 6;
s |= (qq >> 7) & 0x3F; s <<= 8;
s |= (qq & 0x7F);
//if (i < 2) printf("0x%08X\n", s);
samples[i] = __builtin_bswap32(s);
}
}
//=========================================================================
int caribou_smi_write(caribou_smi_st* dev, caribou_smi_channel_en channel,
caribou_smi_sample_complex_int16* samples, size_t length_samples)
{
size_t left_to_write = length_samples * CARIBOU_SMI_BYTES_PER_SAMPLE; // in bytes
size_t written_so_far = 0; // in samples
uint32_t to_millisec = (2 * length_samples * 1000) / CARIBOU_SMI_SAMPLE_RATE;
if (to_millisec < 2) to_millisec = 2;
smi_stream_state_en state = smi_stream_tx_channel;
// apply the state
if (caribou_smi_set_driver_streaming_state(dev, state) != 0)
{
printf("caribou_smi_set_driver_streaming_state -> Failed\n");
return -1;
}
while (left_to_write)
{
// prepare the buffer
caribou_smi_sample_complex_int16* sample_offset = samples + written_so_far;
size_t current_write_len = (left_to_write > dev->native_batch_len) ? dev->native_batch_len : left_to_write;
// make sure the written bytes length is a whole sample multiplication
// if the number of remaining bytes is smaller than sample size -> finish;
current_write_len &= 0xFFFFFFFC;
if (!current_write_len) break;
caribou_smi_generate_data(dev, dev->write_temp_buffer, current_write_len, sample_offset);
int ret = caribou_smi_timeout_write(dev, dev->write_temp_buffer, current_write_len, to_millisec);
if (ret < 0)
{
return -1;
}
else if (ret == 0) break;
written_so_far += current_write_len / CARIBOU_SMI_BYTES_PER_SAMPLE;
left_to_write -= ret;
}
return written_so_far;
}
//=========================================================================
size_t caribou_smi_get_native_batch_samples(caribou_smi_st* dev)
{
//printf("DEBUG: native batch len: %lu\n", dev->native_batch_len / CARIBOU_SMI_BYTES_PER_SAMPLE);
return (dev->native_batch_len / CARIBOU_SMI_BYTES_PER_SAMPLE);
}
//=========================================================================
int caribou_smi_flush_fifo(caribou_smi_st* dev)
{
if (!dev) return -1;
if (!dev->initialized) return -1;
int ret = ioctl(dev->filedesc, SMI_STREAM_IOC_FLUSH_FIFO, 1);
if (ret != 0)
{
ZF_LOGE("failed flushing driver fifos");
return -1;
}
return 0;
}

Wyświetl plik

@ -1,112 +0,0 @@
#ifndef __CARIBOU_SMI_H__
#define __CARIBOU_SMI_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <pthread.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include "kernel/bcm2835_smi.h"
#include "kernel/smi_stream_dev.h"
// DEBUG Information
typedef enum
{
caribou_smi_none = 0,
caribou_smi_lfsr = 1,
caribou_smi_push = 2,
caribou_smi_pull = 3,
} caribou_smi_debug_mode_en;
typedef struct
{
uint32_t error_accum_counter;
uint32_t cur_err_cnt;
uint8_t last_correct_byte;
double error_rate;
uint32_t cnt;
double bitrate;
struct timeval last_time;
} caribou_smi_debug_data_st;
#define CARIBOU_SMI_DEBUG_WORD (0xABCDEF01)
#define CARIBOU_SMI_BYTES_PER_SAMPLE (4)
#define CARIBOU_SMI_SAMPLE_RATE (4000000)
typedef enum
{
caribou_smi_channel_900 = smi_stream_channel_0,
caribou_smi_channel_2400 = smi_stream_channel_1,
} caribou_smi_channel_en;
// Data container
#pragma pack(1)
// associated with CS16 - total 4 bytes / element
typedef struct
{
int16_t i; // LSB
int16_t q; // MSB
} caribou_smi_sample_complex_int16;
typedef struct
{
uint8_t sync;
} caribou_smi_sample_meta;
#pragma pack()
typedef struct
{
int initialized;
int filedesc;
size_t native_batch_len;
uint32_t sample_rate;
smi_stream_state_en state;
uint8_t *read_temp_buffer;
uint8_t *write_temp_buffer;
bool invert_iq;
// debugging
caribou_smi_debug_mode_en debug_mode;
caribou_smi_debug_data_st debug_data;
} caribou_smi_st;
int caribou_smi_init(caribou_smi_st* dev,
void* context);
int caribou_smi_close (caribou_smi_st* dev);
int caribou_smi_check_modules(bool reload);
void caribou_smi_invert_iq(caribou_smi_st* dev, bool invert);
void caribou_smi_set_debug_mode(caribou_smi_st* dev, caribou_smi_debug_mode_en mode);
int caribou_smi_set_driver_streaming_state(caribou_smi_st* dev, smi_stream_state_en state);
smi_stream_state_en caribou_smi_get_driver_streaming_state(caribou_smi_st* dev);
int caribou_smi_read(caribou_smi_st* dev, caribou_smi_channel_en channel,
caribou_smi_sample_complex_int16* buffer, caribou_smi_sample_meta* metadata, size_t length_samples);
int caribou_smi_write(caribou_smi_st* dev, caribou_smi_channel_en channel,
caribou_smi_sample_complex_int16* buffer, size_t length_samples);
size_t caribou_smi_get_native_batch_samples(caribou_smi_st* dev);
void caribou_smi_setup_ios(caribou_smi_st* dev);
void caribou_smi_set_sample_rate(caribou_smi_st* dev, uint32_t sample_rate);
int caribou_smi_flush_fifo(caribou_smi_st* dev);
#ifdef __cplusplus
}
#endif
#endif // __CARIBOU_SMI_H__

Wyświetl plik

@ -1,118 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "CARIBOU_SMI_MODULES"
#define _GNU_SOURCE
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include "zf_log/zf_log.h"
#include "caribou_smi.h"
#include "kernel/smi_stream_dev_gen.h"
#define delete_module(name, flags) syscall(__NR_delete_module, name, flags)
#define init_module(module_image, len, param_values) syscall(__NR_init_module, module_image, len, param_values)
#define finit_module(fd, param_values, flags) syscall(__NR_finit_module, fd, param_values, flags)
//===========================================================
int caribou_smi_check_modules_loaded(char* mod_name)
{
char line[256] = {0};
int found = 0;
FILE *fid = fopen ("/proc/modules", "r");
if (fid == NULL)
{
return -1;
}
while (fgets(line, sizeof(line), fid))
{
char* srch = strstr(line, mod_name);
if (srch != NULL)
{
if (!isspace(srch[strlen(mod_name)])) continue;
found = 1;
}
}
fclose(fid);
return found;
}
//===========================================================
int caribou_smi_remove_module(char* module_name)
{
if (delete_module(module_name, O_NONBLOCK) != 0)
{
ZF_LOGE("Module removing '%s' failed", module_name);
return -1;
}
return 0;
}
//===========================================================
int caribou_smi_insert_smi_modules(char* module_name,
uint8_t* buffer,
size_t len,
const char* params)
{
if (init_module(buffer, len, params) != 0)
{
ZF_LOGE("Module insertion '%s' failed", module_name);
return -1;
}
return 0;
}
//===========================================================
int caribou_smi_check_modules(bool reload)
{
int ret = 0;
int bcm_smi_dev_loaded = caribou_smi_check_modules_loaded("bcm2835_smi_dev");
int smi_stream_dev_loaded = caribou_smi_check_modules_loaded("smi_stream_dev");
int bcm_smi_loaded = caribou_smi_check_modules_loaded("bcm2835_smi");
if (bcm_smi_loaded != 1)
{
ZF_LOGE("SMI base driver not loaded - check device tree");
return -1;
}
if (smi_stream_dev_loaded == 1 && reload)
{
ZF_LOGD("Unloading smi-stream module");
ret = caribou_smi_remove_module("smi_stream_dev");
smi_stream_dev_loaded = 0;
}
if (bcm_smi_dev_loaded == 1)
{
ret = caribou_smi_remove_module("bcm2835_smi_dev");
}
if (ret != 0)
{
ZF_LOGE("Error unloading module from system");
return -1;
}
if (!smi_stream_dev_loaded || reload)
{
ZF_LOGD("Loading smi-stream module");
return caribou_smi_insert_smi_modules("smi_stream_dev", smi_stream_dev, sizeof(smi_stream_dev), "");
}
return 0;
}

Wyświetl plik

@ -1,2 +0,0 @@
# build directories
build

Wyświetl plik

@ -1,3 +0,0 @@
This directory contains generated files.
Do not edit directly.
Editing can be done through the "[root]/driver/" directory.

Wyświetl plik

@ -1,391 +0,0 @@
/**
* Declarations and definitions for Broadcom's Secondary Memory Interface
*
* Written by Luke Wren <luke@raspberrypi.org>
* Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
* Copyright (c) 2010-2012 Broadcom. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2, as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef BCM2835_SMI_H
#define BCM2835_SMI_H
#include <linux/ioctl.h>
#ifndef __KERNEL__
#include <stdint.h>
#include <stdbool.h>
#endif
#define BCM2835_SMI_IOC_MAGIC 0x1
#define BCM2835_SMI_INVALID_HANDLE (~0)
/* IOCTLs 0x100...0x1ff are not device-specific - we can use them */
#define BCM2835_SMI_IOC_GET_SETTINGS _IO(BCM2835_SMI_IOC_MAGIC, 0)
#define BCM2835_SMI_IOC_WRITE_SETTINGS _IO(BCM2835_SMI_IOC_MAGIC, 1)
#define BCM2835_SMI_IOC_ADDRESS _IO(BCM2835_SMI_IOC_MAGIC, 2)
#define BCM2835_SMI_IOC_MAX 2
#define SMI_WIDTH_8BIT 0
#define SMI_WIDTH_16BIT 1
#define SMI_WIDTH_9BIT 2
#define SMI_WIDTH_18BIT 3
/* max number of bytes where DMA will not be used */
#define DMA_THRESHOLD_BYTES 128
#define DMA_BOUNCE_BUFFER_SIZE (1024 * 1024 / 2)
#define DMA_BOUNCE_BUFFER_COUNT 3
struct smi_settings {
int data_width;
/* Whether or not to pack multiple SMI transfers into a
single 32 bit FIFO word */
bool pack_data;
/* Timing for reads (writes the same but for WE)
*
* OE ----------+ +--------------------
* | |
* +----------+
* SD -<==============================>-----------
* SA -<=========================================>-
* <-setup-> <-strobe -> <-hold -> <- pace ->
*/
int read_setup_time;
int read_hold_time;
int read_pace_time;
int read_strobe_time;
int write_setup_time;
int write_hold_time;
int write_pace_time;
int write_strobe_time;
bool dma_enable; /* DREQs */
bool dma_passthrough_enable; /* External DREQs */
int dma_read_thresh;
int dma_write_thresh;
int dma_panic_read_thresh;
int dma_panic_write_thresh;
};
/****************************************************************************
*
* Declare exported SMI functions
*
***************************************************************************/
#ifdef __KERNEL__
#include <linux/dmaengine.h> /* for enum dma_transfer_direction */
#include <linux/of.h>
#include <linux/semaphore.h>
struct bcm2835_smi_instance;
struct bcm2835_smi_bounce_info {
struct semaphore callback_sem;
void *buffer[DMA_BOUNCE_BUFFER_COUNT];
dma_addr_t phys[DMA_BOUNCE_BUFFER_COUNT];
struct scatterlist sgl[DMA_BOUNCE_BUFFER_COUNT];
};
void bcm2835_smi_set_regs_from_settings(struct bcm2835_smi_instance *);
struct smi_settings *bcm2835_smi_get_settings_from_regs(
struct bcm2835_smi_instance *inst);
void bcm2835_smi_write_buf(
struct bcm2835_smi_instance *inst,
const void *buf,
size_t n_bytes);
void bcm2835_smi_read_buf(
struct bcm2835_smi_instance *inst,
void *buf,
size_t n_bytes);
void bcm2835_smi_set_address(struct bcm2835_smi_instance *inst,
unsigned int address);
ssize_t bcm2835_smi_user_dma(
struct bcm2835_smi_instance *inst,
enum dma_transfer_direction dma_dir,
char __user *user_ptr,
size_t count,
struct bcm2835_smi_bounce_info **bounce);
struct bcm2835_smi_instance *bcm2835_smi_get(struct device_node *node);
#endif /* __KERNEL__ */
/****************************************************************
*
* Implementation-only declarations
*
****************************************************************/
#ifdef BCM2835_SMI_IMPLEMENTATION
/* Clock manager registers for SMI clock: */
#define CM_SMI_BASE_ADDRESS ((BCM2708_PERI_BASE) + 0x1010b0)
/* Clock manager "password" to protect registers from spurious writes */
#define CM_PWD (0x5a << 24)
#define CM_SMI_CTL 0x00
#define CM_SMI_DIV 0x04
#define CM_SMI_CTL_FLIP (1 << 8)
#define CM_SMI_CTL_BUSY (1 << 7)
#define CM_SMI_CTL_KILL (1 << 5)
#define CM_SMI_CTL_ENAB (1 << 4)
#define CM_SMI_CTL_SRC_MASK (0xf)
#define CM_SMI_CTL_SRC_OFFS (0)
#define CM_SMI_DIV_DIVI_MASK (0xf << 12)
#define CM_SMI_DIV_DIVI_OFFS (12)
#define CM_SMI_DIV_DIVF_MASK (0xff << 4)
#define CM_SMI_DIV_DIVF_OFFS (4)
/* SMI register mapping:*/
#define SMI_BASE_ADDRESS ((BCM2708_PERI_BASE) + 0x600000)
#define SMICS 0x00 /* control + status register */
#define SMIL 0x04 /* length/count (n external txfers) */
#define SMIA 0x08 /* address register */
#define SMID 0x0c /* data register */
#define SMIDSR0 0x10 /* device 0 read settings */
#define SMIDSW0 0x14 /* device 0 write settings */
#define SMIDSR1 0x18 /* device 1 read settings */
#define SMIDSW1 0x1c /* device 1 write settings */
#define SMIDSR2 0x20 /* device 2 read settings */
#define SMIDSW2 0x24 /* device 2 write settings */
#define SMIDSR3 0x28 /* device 3 read settings */
#define SMIDSW3 0x2c /* device 3 write settings */
#define SMIDC 0x30 /* DMA control registers */
#define SMIDCS 0x34 /* direct control/status register */
#define SMIDA 0x38 /* direct address register */
#define SMIDD 0x3c /* direct data registers */
#define SMIFD 0x40 /* FIFO debug register */
/* Control and Status register bits:
* SMICS_RXF : RX fifo full: 1 when RX fifo is full
* SMICS_TXE : TX fifo empty: 1 when empty.
* SMICS_RXD : RX fifo contains data: 1 when there is data.
* SMICS_TXD : TX fifo can accept data: 1 when true.
* SMICS_RXR : RX fifo needs reading: 1 when fifo more than 3/4 full, or
* when "DONE" and fifo not emptied.
* SMICS_TXW : TX fifo needs writing: 1 when less than 1/4 full.
* SMICS_AFERR : AXI FIFO error: 1 when fifo read when empty or written
* when full. Write 1 to clear.
* SMICS_EDREQ : 1 when external DREQ received.
* SMICS_PXLDAT : Pixel data: write 1 to enable pixel transfer modes.
* SMICS_SETERR : 1 if there was an error writing to setup regs (e.g.
* tx was in progress). Write 1 to clear.
* SMICS_PVMODE : Set to 1 to enable pixel valve mode.
* SMICS_INTR : Set to 1 to enable interrupt on RX.
* SMICS_INTT : Set to 1 to enable interrupt on TX.
* SMICS_INTD : Set to 1 to enable interrupt on DONE condition.
* SMICS_TEEN : Tear effect mode enabled: Programmed transfers will wait
* for a TE trigger before writing.
* SMICS_PAD1 : Padding settings for external transfers. For writes: the
* number of bytes initially written to the TX fifo that
* SMICS_PAD0 : should be ignored. For reads: the number of bytes that will
* be read before the data, and should be dropped.
* SMICS_WRITE : Transfer direction: 1 = write to external device, 0 = read
* SMICS_CLEAR : Write 1 to clear the FIFOs.
* SMICS_START : Write 1 to start the programmed transfer.
* SMICS_ACTIVE : Reads as 1 when a programmed transfer is underway.
* SMICS_DONE : Reads as 1 when transfer finished. For RX, not set until
* FIFO emptied.
* SMICS_ENABLE : Set to 1 to enable the SMI peripheral, 0 to disable.
*/
#define SMICS_RXF (1 << 31)
#define SMICS_TXE (1 << 30)
#define SMICS_RXD (1 << 29)
#define SMICS_TXD (1 << 28)
#define SMICS_RXR (1 << 27)
#define SMICS_TXW (1 << 26)
#define SMICS_AFERR (1 << 25)
#define SMICS_EDREQ (1 << 15)
#define SMICS_PXLDAT (1 << 14)
#define SMICS_SETERR (1 << 13)
#define SMICS_PVMODE (1 << 12)
#define SMICS_INTR (1 << 11)
#define SMICS_INTT (1 << 10)
#define SMICS_INTD (1 << 9)
#define SMICS_TEEN (1 << 8)
#define SMICS_PAD1 (1 << 7)
#define SMICS_PAD0 (1 << 6)
#define SMICS_WRITE (1 << 5)
#define SMICS_CLEAR (1 << 4)
#define SMICS_START (1 << 3)
#define SMICS_ACTIVE (1 << 2)
#define SMICS_DONE (1 << 1)
#define SMICS_ENABLE (1 << 0)
/* Address register bits: */
#define SMIA_DEVICE_MASK ((1 << 9) | (1 << 8))
#define SMIA_DEVICE_OFFS (8)
#define SMIA_ADDR_MASK (0x3f) /* bits 5 -> 0 */
#define SMIA_ADDR_OFFS (0)
/* DMA control register bits:
* SMIDC_DMAEN : DMA enable: set 1: DMA requests will be issued.
* SMIDC_DMAP : DMA passthrough: when set to 0, top two data pins are used by
* SMI as usual. When set to 1, the top two pins are used for
* external DREQs: pin 16 read request, 17 write.
* SMIDC_PANIC* : Threshold at which DMA will panic during read/write.
* SMIDC_REQ* : Threshold at which DMA will generate a DREQ.
*/
#define SMIDC_DMAEN (1 << 28)
#define SMIDC_DMAP (1 << 24)
#define SMIDC_PANICR_MASK (0x3f << 18)
#define SMIDC_PANICR_OFFS (18)
#define SMIDC_PANICW_MASK (0x3f << 12)
#define SMIDC_PANICW_OFFS (12)
#define SMIDC_REQR_MASK (0x3f << 6)
#define SMIDC_REQR_OFFS (6)
#define SMIDC_REQW_MASK (0x3f)
#define SMIDC_REQW_OFFS (0)
/* Device settings register bits: same for all 4 (or 3?) device register sets.
* Device read settings:
* SMIDSR_RWIDTH : Read transfer width. 00 = 8bit, 01 = 16bit,
* 10 = 18bit, 11 = 9bit.
* SMIDSR_RSETUP : Read setup time: number of core cycles between chip
* select/address and read strobe. Min 1, max 64.
* SMIDSR_MODE68 : 1 for System 68 mode (i.e. enable + direction pins,
* rather than OE + WE pin)
* SMIDSR_FSETUP : If set to 1, setup time only applies to first
* transfer after address change.
* SMIDSR_RHOLD : Number of core cycles between read strobe going
* inactive and CS/address going inactive. Min 1, max 64
* SMIDSR_RPACEALL : When set to 1, this device's RPACE value will always
* be used for the next transaction, even if it is not
* to this device.
* SMIDSR_RPACE : Number of core cycles spent waiting between CS
* deassert and start of next transfer. Min 1, max 128
* SMIDSR_RDREQ : 1 = use external DMA request on SD16 to pace reads
* from device. Must also set DMAP in SMICS.
* SMIDSR_RSTROBE : Number of cycles to assert the read strobe.
* min 1, max 128.
*/
#define SMIDSR_RWIDTH_MASK ((1<<31)|(1<<30))
#define SMIDSR_RWIDTH_OFFS (30)
#define SMIDSR_RSETUP_MASK (0x3f << 24)
#define SMIDSR_RSETUP_OFFS (24)
#define SMIDSR_MODE68 (1 << 23)
#define SMIDSR_FSETUP (1 << 22)
#define SMIDSR_RHOLD_MASK (0x3f << 16)
#define SMIDSR_RHOLD_OFFS (16)
#define SMIDSR_RPACEALL (1 << 15)
#define SMIDSR_RPACE_MASK (0x7f << 8)
#define SMIDSR_RPACE_OFFS (8)
#define SMIDSR_RDREQ (1 << 7)
#define SMIDSR_RSTROBE_MASK (0x7f)
#define SMIDSR_RSTROBE_OFFS (0)
/* Device write settings:
* SMIDSW_WWIDTH : Write transfer width. 00 = 8bit, 01 = 16bit,
* 10= 18bit, 11 = 9bit.
* SMIDSW_WSETUP : Number of cycles between CS assert and write strobe.
* Min 1, max 64.
* SMIDSW_WFORMAT : Pixel format of input. 0 = 16bit RGB 565,
* 1 = 32bit RGBA 8888
* SMIDSW_WSWAP : 1 = swap pixel data bits. (Use with SMICS_PXLDAT)
* SMIDSW_WHOLD : Time between WE deassert and CS deassert. 1 to 64
* SMIDSW_WPACEALL : 1: this device's WPACE will be used for the next
* transfer, regardless of that transfer's device.
* SMIDSW_WPACE : Cycles between CS deassert and next CS assert.
* Min 1, max 128
* SMIDSW_WDREQ : Use external DREQ on pin 17 to pace writes. DMAP must
* be set in SMICS.
* SMIDSW_WSTROBE : Number of cycles to assert the write strobe.
* Min 1, max 128
*/
#define SMIDSW_WWIDTH_MASK ((1<<31)|(1<<30))
#define SMIDSW_WWIDTH_OFFS (30)
#define SMIDSW_WSETUP_MASK (0x3f << 24)
#define SMIDSW_WSETUP_OFFS (24)
#define SMIDSW_WFORMAT (1 << 23)
#define SMIDSW_WSWAP (1 << 22)
#define SMIDSW_WHOLD_MASK (0x3f << 16)
#define SMIDSW_WHOLD_OFFS (16)
#define SMIDSW_WPACEALL (1 << 15)
#define SMIDSW_WPACE_MASK (0x7f << 8)
#define SMIDSW_WPACE_OFFS (8)
#define SMIDSW_WDREQ (1 << 7)
#define SMIDSW_WSTROBE_MASK (0x7f)
#define SMIDSW_WSTROBE_OFFS (0)
/* Direct transfer control + status register
* SMIDCS_WRITE : Direction of transfer: 1 -> write, 0 -> read
* SMIDCS_DONE : 1 when a transfer has finished. Write 1 to clear.
* SMIDCS_START : Write 1 to start a transfer, if one is not already underway.
* SMIDCE_ENABLE: Write 1 to enable SMI in direct mode.
*/
#define SMIDCS_WRITE (1 << 3)
#define SMIDCS_DONE (1 << 2)
#define SMIDCS_START (1 << 1)
#define SMIDCS_ENABLE (1 << 0)
/* Direct transfer address register
* SMIDA_DEVICE : Indicates which of the device settings banks should be used.
* SMIDA_ADDR : The value to be asserted on the address pins.
*/
#define SMIDA_DEVICE_MASK ((1<<9)|(1<<8))
#define SMIDA_DEVICE_OFFS (8)
#define SMIDA_ADDR_MASK (0x3f)
#define SMIDA_ADDR_OFFS (0)
/* FIFO debug register
* SMIFD_FLVL : The high-tide mark of FIFO count during the most recent txfer
* SMIFD_FCNT : The current FIFO count.
*/
#define SMIFD_FLVL_MASK (0x3f << 8)
#define SMIFD_FLVL_OFFS (8)
#define SMIFD_FCNT_MASK (0x3f)
#define SMIFD_FCNT_OFFS (0)
#endif /* BCM2835_SMI_IMPLEMENTATION */
#endif /* BCM2835_SMI_H */

Wyświetl plik

@ -1,111 +0,0 @@
/**
* Declarations and definitions for Broadcom's Secondary Memory Interface
*
* Written by David Michaeli <cariboulabs.co@gmail.com>
* Copyright (c) 2021, CaribouLabs.co
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2, as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SMI_STREAM_DEV_H_
#define _SMI_STREAM_DEV_H_
#include <linux/ioctl.h>
#ifndef __KERNEL__
#include <stdint.h>
#include <stdbool.h>
#else
#define BCM2835_SMI_IMPLEMENTATION
#include <linux/broadcom/bcm2835_smi.h>
#endif
#define DEVICE_NAME "smi-stream-dev"
#define DRIVER_NAME "smi-stream-dev"
#define DEVICE_MINOR 0
typedef enum
{
smi_stream_dir_smi_to_device = 0, // device data-bus is highZ (TX)
smi_stream_dir_device_to_smi = 1, // device data-bus is push-pull (RX)
} smi_stream_direction_en;
typedef enum
{
smi_stream_channel_0 = 0,
smi_stream_channel_1 = 1,
smi_stream_channel_max,
} smi_stream_channel_en;
typedef enum
{
smi_stream_idle = 0,
smi_stream_rx_channel_0 = 1,
smi_stream_rx_channel_1 = 2,
smi_stream_tx_channel = 3,
} smi_stream_state_en;
#ifdef __KERNEL__
struct bcm2835_smi_instance {
struct device *dev;
struct smi_settings settings;
__iomem void *smi_regs_ptr;
dma_addr_t smi_regs_busaddr;
struct dma_chan *dma_chan;
struct dma_slave_config dma_config;
struct bcm2835_smi_bounce_info bounce;
struct scatterlist buffer_sgl;
struct clk *clk;
/* Sometimes we are called into in an atomic context (e.g. by
JFFS2 + MTD) so we can't use a mutex */
spinlock_t transaction_lock;
};
#endif // __KERNEL__
// Expansion of ioctls
#define SMI_STREAM_IOC_GET_NATIVE_BUF_SIZE _IO(BCM2835_SMI_IOC_MAGIC,(BCM2835_SMI_IOC_MAX+1))
#define SMI_STREAM_IOC_SET_STREAM_STATUS _IO(BCM2835_SMI_IOC_MAGIC,(BCM2835_SMI_IOC_MAX+2))
#define SMI_STREAM_IOC_SET_STREAM_IN_CHANNEL _IO(BCM2835_SMI_IOC_MAGIC,(BCM2835_SMI_IOC_MAX+3))
#define SMI_STREAM_IOC_SET_FIFO_MULT _IO(BCM2835_SMI_IOC_MAGIC,(BCM2835_SMI_IOC_MAX+4))
#define SMI_STREAM_IOC_SET_ADDR_DIR_OFFSET _IO(BCM2835_SMI_IOC_MAGIC,(BCM2835_SMI_IOC_MAX+5))
#define SMI_STREAM_IOC_SET_ADDR_CH_OFFSET _IO(BCM2835_SMI_IOC_MAGIC,(BCM2835_SMI_IOC_MAX+6))
#define SMI_STREAM_IOC_GET_FIFO_MULT _IO(BCM2835_SMI_IOC_MAGIC,(BCM2835_SMI_IOC_MAX+7))
#define SMI_STREAM_IOC_GET_ADDR_DIR_OFFSET _IO(BCM2835_SMI_IOC_MAGIC,(BCM2835_SMI_IOC_MAX+8))
#define SMI_STREAM_IOC_GET_ADDR_CH_OFFSET _IO(BCM2835_SMI_IOC_MAGIC,(BCM2835_SMI_IOC_MAX+9))
#define SMI_STREAM_IOC_FLUSH_FIFO _IO(BCM2835_SMI_IOC_MAGIC,(BCM2835_SMI_IOC_MAX+10))
#endif /* _SMI_STREAM_DEV_H_ */

Wyświetl plik

@ -1,256 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "CARIBOU_SMI_Utils"
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "smi_utils.h"
#include "zf_log/zf_log.h"
//=========================================================================
void smi_utils_set_realtime_priority(int priority_deter)
{
int ret;
// We'll operate on the currently running thread.
pthread_t this_thread = pthread_self();
// struct sched_param is used to store the scheduling priority
struct sched_param params;
// We'll set the priority to the maximum.
params.sched_priority = sched_get_priority_max(SCHED_FIFO) - priority_deter;
ZF_LOGI("Trying to set thread realtime prio = %d", params.sched_priority);
// Attempt to set thread real-time priority to the SCHED_FIFO policy
ret = pthread_setschedparam(this_thread, SCHED_FIFO, &params);
if (ret != 0)
{
// Print the error
ZF_LOGE("Unsuccessful in setting thread realtime prio");
return;
}
// Now verify the change in thread priority
int policy = 0;
ret = pthread_getschedparam(this_thread, &policy, &params);
if (ret != 0)
{
ZF_LOGE("Couldn't retrieve real-time scheduling paramers");
return;
}
// Check the correct policy was applied
if(policy != SCHED_FIFO)
{
ZF_LOGE("Scheduling is NOT SCHED_FIFO!");
} else {
ZF_LOGI("SCHED_FIFO OK");
}
// Print thread scheduling priority
ZF_LOGI("Thread priority is %d", params.sched_priority);
}
//=========================================================================
void smi_utils_dump_hex(const void* data, size_t size)
{
char ascii[17];
size_t i, j;
ascii[16] = '\0';
for (i = 0; i < size; ++i)
{
printf("%02X ", ((unsigned char*)data)[i]);
if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~')
{
ascii[i % 16] = ((unsigned char*)data)[i];
}
else
{
ascii[i % 16] = '.';
}
if ((i+1) % 8 == 0 || i+1 == size)
{
printf(" ");
if ((i+1) % 16 == 0)
{
printf("| %s \n", ascii);
}
else if (i+1 == size)
{
ascii[(i+1) % 16] = '\0';
if ((i+1) % 16 <= 8)
{
printf(" ");
}
for (j = (i+1) % 16; j < 16; ++j)
{
printf(" ");
}
printf("| %s \n", ascii);
}
}
}
}
//=========================================================================
void smi_utils_dump_hex_simple(const void* data, size_t size, size_t delim)
{
unsigned int temp = 0;
for (unsigned int i = 0; i < size; ++i)
{
temp ++;
printf("%02X ", ((unsigned char*)data)[i]);
if (delim > 0 && temp > delim)
{
temp = 0;
printf("\n");
}
}
printf("\n");
}
//=========================================================================
void smi_utils_dump_bin(const uint8_t* data, size_t size)
{
char str[16] = {0};
for (size_t i = 0; i < size; i++)
{
if (i % 8 == 0) printf("\n");
int k = 0;
uint8_t b = data[i];
for (k = 0; k < 8; k++)
{
str[k] = (b&0x80)==0?'0':'1';
b <<= 1;
}
str[k] = ' ';
printf("%s", str);
}
printf("\n");
}
//=========================================================================
void smi_utils_print_bin(uint32_t v)
{
char str[48] = {0};
int i = 0;
for (int k = 0; k < 32; k++)
{
if (k%8==0) str[i++]=' ';
str[i++] = (v&0x80000000)==0?'0':'1';
v <<= 1;
}
printf("%s\n", str);
}
//=========================================================================
int smi_utils_allocate_buffer_vec(uint8_t*** mat, int num_buffers, int buffer_size)
{
ZF_LOGI("Allocating buffer vectors");
(*mat) = (uint8_t**) malloc( num_buffers * sizeof(uint8_t*) );
if ((*mat) == NULL)
{
ZF_LOGE("buffer vector allocation failed");
return -1;
}
memset( (*mat), 0, num_buffers * sizeof(uint8_t*) );
int failed = 0;
int i;
for (i = 0; i < num_buffers; i++)
{
(*mat)[i] = (uint8_t*)calloc( buffer_size, sizeof(uint8_t) );
if ((*mat)[i] == NULL)
{
failed = 1;
break;
}
}
if (failed)
{
for (int j = 0; j < i; j++)
{
free((*mat)[j]);
}
free((*mat));
ZF_LOGE("buffer (%d) allocation failed", i);
return -1;
}
return 0;
}
//=========================================================================
void smi_utils_release_buffer_vec(uint8_t** mat, int num_buffers, int buffer_size)
{
ZF_LOGI("Releasing buffer vectors");
if (mat == NULL)
return;
for (int i = 0; i < num_buffers; i ++)
{
if (mat[i] != NULL) free (mat[i]);
}
free(mat);
}
//=========================================================================
int smi_utils_search_offset_in_buffer(uint8_t *buff, int len)
{
bool succ = false;
int off = 0;
while (!succ)
{
if ( (buff[off + 0] & 0xC0) == 0xC0 &&
(buff[off + 4] & 0xC0) == 0xC0 &&
(buff[off + 8] & 0xC0) == 0xC0 &&
(buff[off + 12] & 0xC0) == 0xC0 )
return off;
off ++;
}
return -1;
}
//=========================================================================
uint8_t smi_utils_lfsr(uint8_t n)
{
uint8_t bit = ((n >> 2) ^ (n >> 3)) & 1;
return (n >> 1) | (bit << 7);
}
//=========================================================================
double smi_calculate_performance(size_t bytes, struct timeval *old_time, double old_mbps)
{
struct timeval current_time = {0,0};
gettimeofday(&current_time, NULL);
double elapsed_us = (current_time.tv_sec - old_time->tv_sec) + ((double)(current_time.tv_usec - old_time->tv_usec)) / 1000000.0;
double speed_mbps = (double)(bytes * 8) / elapsed_us / 1e6;
old_time->tv_sec = current_time.tv_sec;
old_time->tv_usec = current_time.tv_usec;
return old_mbps * 0.98 + speed_mbps * 0.02;
}
//=========================================================================
unsigned int smi_utils_count_bit(unsigned int x)
{
x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
x = (x & 0x0000FFFF) + ((x >> 16)& 0x0000FFFF);
return x;
}

Wyświetl plik

@ -1,67 +0,0 @@
#ifndef __UTILS_H__
#define __UTILS_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <pthread.h>
#include <stdint.h>
#define TIMING_PERF_SYNC (0)
#if (TIMING_PERF_SYNC)
#define TIMING_PERF_SYNC_VARS \
struct timeval tv_pre = {0}; \
struct timeval tv_post = {0}; \
long long total_samples = 0,last_total_samples = 0; \
double time_pre = 0, batch_time = 0, sample_rate = 0; \
double time_post = 0, process_time = 0; \
double temp_pre; \
double num_samples = 0, num_samples_avg = 0;
#define TIMING_PERF_SYNC_TICK \
gettimeofday(&tv_pre, NULL);
#define TIMING_PERF_SYNC_TOCK \
gettimeofday(&tv_post, NULL); \
num_samples = (double)(st->read_ret_value) / 4.0; \
num_samples_avg = num_samples_avg*0.1 + num_samples*0.9; \
temp_pre = tv_pre.tv_sec + ((double)(tv_pre.tv_usec)) / 1e6; \
time_post = tv_post.tv_sec + ((double)(tv_post.tv_usec)) / 1e6; \
batch_time = temp_pre - time_pre; \
sample_rate = sample_rate*0.1 + (num_samples / batch_time) * 0.9; \
process_time = process_time*0.1 + (time_post - temp_pre)*0.9; \
time_pre = temp_pre; \
total_samples += st->read_ret_value; \
if ((total_samples - last_total_samples) > 4000000*4) \
{ \
last_total_samples = total_samples; \
ZF_LOGD("sample_rate = %.2f SPS, process_time = %.2f usec" \
", num_samples_avg = %.1f", \
sample_rate, process_time * 1e6, num_samples_avg); \
}
#else
#define TIMING_PERF_SYNC_VARS
#define TIMING_PERF_SYNC_TICK
#define TIMING_PERF_SYNC_TOCK
#endif
void smi_utils_set_realtime_priority(int priority_deter);
void smi_utils_dump_hex(const void* data, size_t size);
void smi_utils_dump_hex_simple(const void* data, size_t size, size_t delim);
void smi_utils_dump_bin(const uint8_t* data, size_t size);
void smi_utils_print_bin(const uint32_t v);
int smi_utils_allocate_buffer_vec(uint8_t*** mat, int num_buffers, int buffer_size);
void smi_utils_release_buffer_vec(uint8_t** mat, int num_buffers, int buffer_size);
int smi_utils_search_offset_in_buffer(uint8_t *buff, int len);
uint8_t smi_utils_lfsr(uint8_t n);
double smi_calculate_performance(size_t bytes, struct timeval *old_time, double old_mbps);
unsigned int smi_utils_count_bit(unsigned int x);
#ifdef __cplusplus
}
#endif
#endif // __UTILS_H__

Wyświetl plik

@ -1,183 +0,0 @@
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "CARIBOU_SMI_Test"
#include "zf_log/zf_log.h"
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <unistd.h>
#include <time.h>
#include "caribou_smi.h"
#include "utils.h"
caribou_smi_st dev = {0};
char program_name[] = "test_caribou_smi.c";
#define NUM_MS (5)
#define NUM_SAMPLES (NUM_MS * 4096)
#define SIZE_OF_SAMPLE (4)
#define NUM_OF_BUFFERS (2)
//==============================================
void swap_little_big (uint32_t *v)
{
uint8_t b[4];
b[0] = (uint8_t) ((*v) >> 24u);
b[1] = (uint8_t) ((*v) >> 16u);
b[2] = (uint8_t) ((*v) >> 8u);
b[3] = (uint8_t) ((*v) >> 0u);
*v = *((uint32_t*)(b));
}
//==============================================
void print_iq(uint32_t* array, int len)
{
printf("Values I/Q:\n");
for (int i=0; i<len; i++)
{
unsigned int v = array[i];
//swap_little_big (&v);
int16_t q_val = (v>> 1) & (0x1FFF);
int16_t i_val = (v>>17) & (0x1FFF);
if (q_val >= 0x1000) q_val-=0x2000;
if (i_val >= 0x1000) i_val-=0x2000;
float fi = i_val, fq = q_val;
float mod = sqrt(fi*fi + fq*fq);
float arg = atan2(fq, fi);
printf("%08X, %d, %d, %.4f, %.2f\n", v, i_val, q_val, mod, arg);
}
}
void caribou_smi_data_event(void *ctx, // The context of the requesting application
void *serviced_context, // the context of the session within the app
caribou_smi_stream_type_en type, // which type of stream is it? read / write?
caribou_smi_event_type_en ev, // the event (start / stop)
caribou_smi_channel_en ch, // which channel (900 / 2400)
size_t num_samples, // for "read stream only" - number of read data bytes in buffer
caribou_smi_sample_complex_int16 *cplx_vec, // for "read" - complex vector of samples to be analyzed
// for "write" - complex vector of samples to be written into
caribou_smi_sample_meta *metadat_vec, // for "read" - the metadata send by the receiver for each sample
// for "write" - the metadata to be written by app for each sample
size_t total_length_samples)
{
if (ev == caribou_smi_event_type_start)
{
ZF_LOGD("start event: stream batch length: %u samples\n", total_length_samples);
return;
}
else if (ev == caribou_smi_event_type_end)
{
ZF_LOGD("end event: stream batch length: %u samples\n", total_length_samples);
return;
}
switch(type)
{
//-------------------------------------------------------
case caribou_smi_stream_type_read:
{
ZF_LOGD("data event: stream channel %d, received %u samples\n", ch, num_samples);
//print_iq((uint32_t*)buffer, 8);
/*for (int i = 0; i< byte_count; i++)
{
uint8_t dist = (uint8_t)(buffer[i] - last_byte);
if ( dist > 1)
{
err_count ++;
float bER = (float)(err_count) / (float)(c);
printf("ERR > at %d, dist: %d, V: %d, bER: %.7f\n", c, dist, buffer[i], bER);
}
last_byte = buffer[i];
c++;
}*/
if ( num_samples > 0 )
{
/*printf("CHUNK %d> %02x %02x %02x %02x...\n", c, buffer[0],
buffer[1],
buffer[2],
buffer[3]);*/
/*
printf("CUR %d CHUNK > %02x %02x %02x %02x ... %02x %02x %02x %02x\n", c,
buffer[0],
buffer[1],
buffer[2],
buffer[3],
buffer[byte_count-4],
buffer[byte_count-3],
buffer[byte_count-2],
buffer[byte_count-1]);*/
}
}
break;
//-------------------------------------------------------
case caribou_smi_stream_type_write:
{
}
break;
//-------------------------------------------------------
default:
break;
}
}
//==============================================
void caribou_smi_error_event( void *ctx, caribou_smi_channel_en ch, caribou_smi_error_en err)
{
ZF_LOGD("Error (from %s) occured in channel %d, err# %d (%s)\n", (char*)ctx, ch, err, caribou_smi_get_error_string(err));
}
//==============================================
int main_single_read()
{
int read_count = 4096;
uint32_t buffer[read_count];
char* b8 = (char*)buffer;
caribou_smi_init(&dev, caribou_smi_error_event, program_name);
caribou_smi_timeout_read(&dev, address, b8, read_count*sizeof(uint32_t), 1000);
smi_utils_dump_hex(b8, read_count*sizeof(uint32_t));
print_iq(buffer, read_count);
caribou_smi_close (&dev);
return 0;
}
//==============================================
int main_stream_read()
{
caribou_smi_init(&dev, caribou_smi_error_event, program_name);
int stream_id = caribou_smi_setup_stream(&dev,
caribou_smi_stream_type_read,
channel,
caribou_smi_data_event,
NULL);
sleep(1);
caribou_smi_run_pause_stream (&dev, stream_id, 1);
printf("Listening on stream_id = %d\n", stream_id);
printf("Press ENTER to exit...\n");
getchar();
printf("ENTER pressed...\n");
//caribou_smi_run_pause_stream (&dev, stream_id, 0);
caribou_smi_destroy_stream(&dev, stream_id);
caribou_smi_close (&dev);
return 0;
}
//==============================================
int main()
{
main_stream_read();
return 0;
}

Wyświetl plik

@ -1,252 +0,0 @@
#include "cariboulite.h"
#include "cariboulite_setup.h"
#include "cariboulite_radio.h"
// ----------------------
// INTERNAL DATA TYPES
// ----------------------
typedef struct
{
cariboulite_lib_version_st lib_version;
cariboulite_signal_handler sighandler;
void* sig_context;
bool initialized;
cariboulite_log_level_en log_level;
int signal_shown;
} cariboulite_api_context_st;
// ----------------------
// STATIC VARIABLES
// ----------------------
CARIBOULITE_CONFIG_STATIC_DEFAULT(sys);
static cariboulite_api_context_st ctx = {
.lib_version = {0},
.sighandler = NULL,
.sig_context = NULL,
.initialized = false,
.log_level = cariboulite_log_level_verbose,
.signal_shown = 0,
};
//=============================================================================
static void internal_sighandler( struct sys_st_t *sys,
void* context,
int signal_number,
siginfo_t *si)
{
if (ctx.signal_shown != signal_number)
{
fprintf(stderr, "Received signal %d", signal_number);
ctx.signal_shown = signal_number;
}
if (ctx.sighandler) ctx.sighandler(ctx.sig_context, signal_number, si);
}
//=============================================================================
bool cariboulite_detect_connected_board(cariboulite_version_en *hw_ver, char* name, char *uuid)
{
hat_board_info_st hat;
if (hat_detect_board(&hat) == 0)
{
return false;
}
switch (hat.numeric_product_id)
{
case system_type_cariboulite_full:
if (hw_ver) *hw_ver = cariboulite_full;
if (name) sprintf(name, "CaribouLite 6G");
break;
case system_type_cariboulite_ism:
if (hw_ver) *hw_ver = cariboulite_ism;
if (name) sprintf(name, "CaribouLite ISM");
break;
case system_type_unknown:
if (hw_ver) *hw_ver = cariboulite_unknown;
if (name) sprintf(name, "CaribouLite Unknown");
default: break;
}
if (uuid) sprintf(uuid, "%s", hat.product_uuid);
return true;
}
//=============================================================================
int cariboulite_init(bool force_fpga_prog, cariboulite_log_level_en log_lvl)
{
sys.force_fpga_reprogramming = force_fpga_prog;
cariboulite_set_log_level(log_lvl);
if (cariboulite_init_driver(&sys, NULL)!=0)
{
fprintf(stderr, "CaribouLite driver init failed, terminating...");
return -1;
}
cariboulite_setup_signal_handler (&sys, internal_sighandler, signal_handler_op_override, &sys);
ctx.initialized = true;
return 0;
}
//=============================================================================
void cariboulite_close(void)
{
if (!ctx.initialized) return;
ctx.initialized = false;
cariboulite_release_driver(&sys);
}
//=============================================================================
bool cariboulite_is_initialized(void)
{
return ctx.initialized;
}
//=============================================================================
void cariboulite_register_signal_handler ( cariboulite_signal_handler handler,
void *context)
{
ctx.sighandler = handler;
ctx.sig_context = context;
}
//=============================================================================
void cariboulite_get_lib_version(cariboulite_lib_version_st* v)
{
cariboulite_lib_version(v);
}
//=============================================================================
unsigned int cariboulite_get_sn()
{
uint32_t sn = 0;
int count = 0;
cariboulite_get_serial_number(&sys, &sn, &count);
return sn;
}
//=============================================================================
cariboulite_radio_state_st* cariboulite_get_radio(cariboulite_channel_en ch)
{
return cariboulite_get_radio_handle(&sys, ch);
}
//=============================================================================
cariboulite_version_en cariboulite_get_version()
{
system_type_en type = cariboulite_get_system_type(&sys);
switch(type)
{
case cariboulite_full: return cariboulite_full; break;
case cariboulite_ism: return cariboulite_ism; break;
case system_type_unknown:
default: return cariboulite_unknown; break;
}
return cariboulite_unknown;
}
//=============================================================================
bool cariboulite_frequency_available(cariboulite_channel_en ch, float freq_hz)
{
if (ch == cariboulite_channel_s1g)
{
return (freq_hz >= CARIBOULITE_S1G_MIN1 && freq_hz <= CARIBOULITE_S1G_MAX1 ||
freq_hz >= CARIBOULITE_S1G_MIN2 && freq_hz <= CARIBOULITE_S1G_MAX2);
}
else if (ch == cariboulite_channel_hif)
{
cariboulite_version_en ver = cariboulite_get_version();
if (ver == cariboulite_full)
{
return (freq_hz >= CARIBOULITE_6G_MIN && freq_hz <= CARIBOULITE_6G_MAX);
}
else if (ver == cariboulite_ism)
{
return (freq_hz >= CARIBOULITE_2G4_MIN && freq_hz <= CARIBOULITE_2G4_MAX);
}
}
return false;
}
//=============================================================================
int cariboulite_get_num_frequency_ranges(cariboulite_channel_en ch)
{
if (ch == cariboulite_channel_s1g) return 2;
else if (ch == cariboulite_channel_hif) return 1;
return -1;
}
//=============================================================================
int cariboulite_get_frequency_limits(cariboulite_channel_en ch, float *freq_low, float *freq_hi, int* num_ranges)
{
if (ch == cariboulite_channel_s1g)
{
freq_low[0] = CARIBOULITE_S1G_MIN1;
freq_hi[0] = CARIBOULITE_S1G_MAX1;
freq_low[1] = CARIBOULITE_S1G_MIN2;
freq_hi[1] = CARIBOULITE_S1G_MAX2;
if (num_ranges) *num_ranges = 2;
}
else if (ch == cariboulite_channel_hif)
{
cariboulite_version_en ver = cariboulite_get_version();
if (ver == cariboulite_full)
{
freq_low[0] = CARIBOULITE_6G_MIN;
freq_hi[0] = CARIBOULITE_6G_MAX;
if (num_ranges) *num_ranges = 1;
}
else if (ver == cariboulite_ism)
{
freq_low[0] = CARIBOULITE_2G4_MIN;
freq_hi[0] = CARIBOULITE_2G4_MAX;
if (num_ranges) *num_ranges = 1;
}
else
{
return -1;
}
}
else
{
return -1;
}
return 0;
}
//=============================================================================
int cariboulite_get_channel_name(cariboulite_channel_en ch, char* name, size_t max_len)
{
if (ch == cariboulite_channel_s1g)
{
snprintf(name, max_len-1, "CaribouLite S1G");
return 0;
}
else if (ch == cariboulite_channel_hif)
{
cariboulite_version_en ver = cariboulite_get_version();
if (ver == cariboulite_full)
{
snprintf(name, max_len-1, "CaribouLite 6GHz");
return 0;
}
else if (ver == cariboulite_ism)
{
snprintf(name, max_len-1, "CaribouLite 2.4GHz");
return 0;
}
}
return -1;
}
//=============================================================================
int cariboulite_flush_pipeline()
{
// request the smi driver to flush its drivers fifo
return caribou_smi_flush_fifo(&sys.smi);
}

Wyświetl plik

@ -1,228 +0,0 @@
/**
* @file cariboulite.h
* @author David Michaeli
* @date September 2023
* @brief Main Init/Close API
*
* A high level management API for CaribouLite
*/
#ifndef __CARIBOULITE_H__
#define __CARIBOULITE_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <signal.h>
#include "cariboulite_radio.h"
/**
* @brief library version
*/
typedef struct
{
int major_version;
int minor_version;
int revision;
} cariboulite_lib_version_st;
/**
* @brief Log Level
*/
typedef enum
{
cariboulite_log_level_verbose, /**< Full */
cariboulite_log_level_info, /**< partial - no debug */
cariboulite_log_level_none, /**< none - errors only*/
} cariboulite_log_level_en;
/**
* @brief System Type (version)
*/
typedef enum
{
cariboulite_unknown = 0,
cariboulite_full = 1,
cariboulite_ism = 2,
} cariboulite_version_en;
/**
* @brief custom signal handler
*/
typedef void (*cariboulite_signal_handler)( void* context, // custom context - can be a higher level app class
int signal_number, // the signal number
siginfo_t *si);
/**
* @brief check if board connected (without initing it)
*
* This function attempts to read the HAT information and checks if a
* CaribouLite is registerred in the OS. If so gets its details.
* this fucntion is good to check whether the board is mounted without the need
* to initialize it. Preferably this is a simple check before we start working
* - kind of a sanity check.
*
* @param hw_ver the type of HW (full / ism) as ENUM (nullable is not needed)
* @param name the type of HW in textual manner - preallocate the string (at least 32 bytes)
* (nullable is not needed)
* @uuid uuid if this is needed, the user needs to provide a preallocated string 64 byte typical
* (nullable if not needed)
* @return true - when board was detected
* false - board was not detected and then other parameters will not be valid
*/
bool cariboulite_detect_connected_board(cariboulite_version_en *hw_ver, char* name, char *guid);
/**
* @brief initialize the system
*
* This function performs fully entry initialization of the system and
* a short self-test sequence to communication and check all the components
* respond.
*
* @param force_fpga_prog force the FPGA to program (even if it is already programmed
* this will have a penalty of around 3 seconds on init. If false
* and the FPGA is already programmed (typically when this is not
* the first time a program has run since last boot session), the program
* will not rerun the FPGA programming process.
* @param log_lvl the logging level according to 'cariboulite_log_level_en'
* @return success / fail codes according to "cariboulite_errors_en"
*/
int cariboulite_init(bool force_fpga_prog, cariboulite_log_level_en log_lvl);
/**
* @brief Release resources
*
* Releasing resources taken during init and program execution. Should be
* called at the end of the session.
*
* @param sys a pre-allocated device handle structure
*/
void cariboulite_close(void);
/**
* @brief Returns init status
*
* checks whether the driver is initialized
*
* @return boolean result (true = initialized)
*/
bool cariboulite_is_initialized(void);
/**
* @brief Register an explicit linux signal handler in the application level
*
* If a linux signal occures it is caught by the system. The user may want to be
* notified on the signal in the app level. This is done by registering a handler
* function with this fucntion.
*
* @param sys a pre-allocated device handle structure
* @param handler a handler function with the following prototype:
* void (*signal_handler)( void* context, // custom context - can be a higher level app class
* int signal_number, // the signal number
* siginfo_t *si);
* @param context this void* pointer may contain an app specific handle to be passed to the explicit signal handler.
* @return always 0 (success)
*/
void cariboulite_register_signal_handler ( cariboulite_signal_handler handler,
void *context);
/**
* @brief Get lib version
*
* @param v a struct containing the version information
*/
void cariboulite_get_lib_version(cariboulite_lib_version_st* v);
/**
* @brief Get board serial number
*
* @return board serial number (32 bit)
*/
unsigned int cariboulite_get_sn();
/**
* @brief Getting the used radio handle
*
* After initializing the drivers, a radio device is created and stored in
* the device driver main struct. To manipulate the radio features, this radio
* handle (pointer) needs to be obtained by the user. This handle is normally
* passed to the radio manipulation functions in "cariboulite_radio.h"
*
* @param type the radio channel (6G/2.4G or ISM)
* @return the handle of the channel, or NULL if invalid channel id
*/
cariboulite_radio_state_st* cariboulite_get_radio(cariboulite_channel_en ch);
/**
* @brief Getting CaribouLite version
*
* Returns the version of the hardware - ISM / 6G / Unknown
* ISM has two channels - 900MHz and 2.4 GHz
* 6G has two channels - 900MHz and 6000MHz
*
* @return according to cariboulite_version_en
*/
cariboulite_version_en cariboulite_get_version(void);
/**
* @brief Getting frequency availability
*
* Given a certain frequency (in Hz) checking if that frequency is available in the
* connected hardware
*
* @return true / false
*/
bool cariboulite_frequency_available(cariboulite_channel_en ch, float freq_hz);
/**
* @brief Getting the number frequency ranges
*
* Each channel has its frequency capabilities. in the ISM channel there are 2
* ranges, while in the HiF there is a single range. This function returns the number
* of available ranges per channel. To get the actual limits use 'cariboulite_get_frequency_limits'
*
* @return number of ranges or -1 if the channel doesn't exist
*/
int cariboulite_get_num_frequency_ranges(cariboulite_channel_en ch);
/**
* @brief Getting frequency ranges limits
*
* freq_low and freq_hi need to be pre-allocated according to 'cariboulite_get_num_frequency_ranges'
* then all the minimum values will be in the freq_low list and the corresponding max values will be in
* freq_hi. All frequencies in Hz
* num_ranges returns the number of written ranges
*
* @return 0 for success or -1 if channel is wrong
*/
int cariboulite_get_frequency_limits(cariboulite_channel_en ch, float *freq_low, float *freq_hi, int* num_ranges);
/**
* @brief Get channel name
*
* Returns the string name of a channel
*
* @param ch the chosen channel
* @param name a pre-allocated char array
* @param max_len the size of the pre-allocated char array
* @return 0 (success) or -1 (failed - when channel is incorrect)
*/
int cariboulite_get_channel_name(cariboulite_channel_en ch, char* name, size_t max_len);
/**
* @brief Flush driver FIFO
*
* Removing all items in the pipeline (drivers kfifo)
*
* @return 0 (success) or -1 (failed - when channel is incorrect)
*/
int cariboulite_flush_pipeline(void);
#ifdef __cplusplus
}
#endif
#endif // __CARIBOULITE_H__

Wyświetl plik

@ -1,93 +0,0 @@
#ifndef __CARIBOULITE_CONFIG_DEFAULT_H__
#define __CARIBOULITE_CONFIG_DEFAULT_H__
#ifdef __cplusplus
extern "C" {
#endif
// PINOUT SPI
#define CARIBOULITE_SPI_DEV 1
#define CARIBOULITE_MOSI 20
#define CARIBOULITE_SCK 21
#define CARIBOULITE_MISO 19
// PINOUT FPGA
#define CARIBOULITE_FPGA_SPI_CHANNEL 0
#define CARIBOULITE_FPGA_SS 18
#define CARIBOULITE_FPGA_CDONE 27
#define CARIBOULITE_FPGA_CRESET 26
#define CARIBOULITE_FPGA_SOFT_RESET 4
// PINOUT AT86 - AT86RF215
#define CARIBOULITE_MODEM_SPI_CHANNEL 1
#define CARIBOULITE_MODEM_SS 17
#define CARIBOULITE_MODEM_IRQ 22
#define CARIBOULITE_MODEM_RESET 23
// PINOUT MIXER - RFFC5072
#define CARIBOULITE_MIXER_SPI_CHANNEL 2
#define CARIBOULITE_MIXER_SS 16
#define CARIBOULITE_MIXER_RESET 5
//=======================================================================================
// SYSTEM DEFINITIONS & CONFIGURATIONS
//=======================================================================================
#define CARIBOULITE_CONFIG_DEFAULT(a) \
sys_st(a)={ \
.board_info = {0}, \
.spi_dev = \
{ \
.miso = CARIBOULITE_MISO, \
.mosi = CARIBOULITE_MOSI, \
.sck = CARIBOULITE_SCK, \
.initialized = 0, \
}, \
.smi = \
{ \
.initialized = 0, \
}, \
.fpga = \
{ \
.reset_pin = CARIBOULITE_FPGA_CRESET, \
.soft_reset_pin = CARIBOULITE_FPGA_SOFT_RESET, \
.cs_pin = CARIBOULITE_FPGA_SS, \
.spi_dev = CARIBOULITE_SPI_DEV, \
.spi_channel = CARIBOULITE_FPGA_SPI_CHANNEL, \
.prog_dev = \
{ \
.cs_pin = CARIBOULITE_FPGA_SS, \
.cdone_pin = CARIBOULITE_FPGA_CDONE, \
.reset_pin = CARIBOULITE_FPGA_CRESET, \
}, \
.initialized = 0, \
}, \
.modem = \
{ \
.reset_pin = CARIBOULITE_MODEM_RESET, \
.irq_pin = CARIBOULITE_MODEM_IRQ, \
.cs_pin = CARIBOULITE_MODEM_SS, \
.spi_dev = CARIBOULITE_SPI_DEV, \
.spi_channel = CARIBOULITE_MODEM_SPI_CHANNEL, \
.initialized = 0, \
.override_cal = true, \
}, \
.mixer = \
{ \
.cs_pin = CARIBOULITE_MIXER_SS, \
.reset_pin = CARIBOULITE_MIXER_RESET, \
.ref_freq_hz = 32e6, \
.initialized = 0, \
}, \
.reset_fpga_on_startup = 1, \
.system_status = sys_status_unintialized, \
}
#define CARIBOULITE_CONFIG_STATIC_DEFAULT(a) \
static CARIBOULITE_CONFIG_DEFAULT(a)
#ifdef __cplusplus
}
#endif
#endif //__CARIBOULITE_CONFIG_DEFAULT_H__

Wyświetl plik

@ -1,113 +0,0 @@
/*
* This file was automatically generated using the 'generate_bin_blob' tool
* Modification of this file is not recommanded - please re-generate it
* as needed and embed in the code library.
*/
#ifndef __cariboulite_dtbo_h__
#define __cariboulite_dtbo_h__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdint.h>
#include <time.h>
/*
* Time tagging of the module through the 'struct tm' structure
* Date: 2023-02-14
* Time: 10:19:31
*/
struct tm cariboulite_dtbo_date_time = {
.tm_sec = 31,
.tm_min = 19,
.tm_hour = 10,
.tm_mday = 14,
.tm_mon = 1, /* +1 */
.tm_year = 123, /* +1900 */
};
/*
* Data blob of variable cariboulite_dtbo:
* Size: 1100 bytes
* Original filename: ./cariboulite.dtbo
*/
uint8_t cariboulite_dtbo[] = {
0xD0, 0x0D, 0xFE, 0xED, 0x00, 0x00, 0x04, 0x4C, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x03, 0xD0,
0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x03, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x62, 0x72, 0x63, 0x6D,
0x2C, 0x62, 0x63, 0x6D, 0x32, 0x38, 0x33, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x66, 0x72, 0x61, 0x67, 0x6D, 0x65, 0x6E, 0x74, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
0x5F, 0x5F, 0x6F, 0x76, 0x65, 0x72, 0x6C, 0x61, 0x79, 0x5F, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x01,
0x73, 0x6D, 0x69, 0x5F, 0x64, 0x65, 0x76, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15,
0x00, 0x00, 0x00, 0x00, 0x62, 0x72, 0x63, 0x6D, 0x2C, 0x62, 0x63, 0x6D, 0x32, 0x38, 0x33, 0x35,
0x2D, 0x73, 0x6D, 0x69, 0x2D, 0x64, 0x65, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x12, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1D, 0x6F, 0x6B, 0x61, 0x79, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
0x66, 0x72, 0x61, 0x67, 0x6D, 0x65, 0x6E, 0x74, 0x40, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
0x5F, 0x5F, 0x6F, 0x76, 0x65, 0x72, 0x6C, 0x61, 0x79, 0x5F, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x24, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x00,
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1D, 0x6F, 0x6B, 0x61, 0x79,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
0x66, 0x72, 0x61, 0x67, 0x6D, 0x65, 0x6E, 0x74, 0x40, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
0x5F, 0x5F, 0x6F, 0x76, 0x65, 0x72, 0x6C, 0x61, 0x79, 0x5F, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x01,
0x73, 0x6D, 0x69, 0x5F, 0x70, 0x69, 0x6E, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09,
0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D,
0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19,
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x05,
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05,
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05,
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05,
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x54,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x5F, 0x5F, 0x73, 0x79, 0x6D, 0x62, 0x6F, 0x6C,
0x73, 0x5F, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x66,
0x2F, 0x66, 0x72, 0x61, 0x67, 0x6D, 0x65, 0x6E, 0x74, 0x40, 0x32, 0x2F, 0x5F, 0x5F, 0x6F, 0x76,
0x65, 0x72, 0x6C, 0x61, 0x79, 0x5F, 0x5F, 0x2F, 0x73, 0x6D, 0x69, 0x5F, 0x70, 0x69, 0x6E, 0x73,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x5F, 0x5F, 0x66, 0x69,
0x78, 0x75, 0x70, 0x73, 0x5F, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15,
0x00, 0x00, 0x00, 0x6F, 0x2F, 0x66, 0x72, 0x61, 0x67, 0x6D, 0x65, 0x6E, 0x74, 0x40, 0x30, 0x3A,
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3A, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x73, 0x2F, 0x66, 0x72, 0x61, 0x67, 0x6D, 0x65, 0x6E,
0x74, 0x40, 0x30, 0x2F, 0x5F, 0x5F, 0x6F, 0x76, 0x65, 0x72, 0x6C, 0x61, 0x79, 0x5F, 0x5F, 0x2F,
0x73, 0x6D, 0x69, 0x5F, 0x64, 0x65, 0x76, 0x3A, 0x73, 0x6D, 0x69, 0x5F, 0x68, 0x61, 0x6E, 0x64,
0x6C, 0x65, 0x3A, 0x30, 0x00, 0x2F, 0x66, 0x72, 0x61, 0x67, 0x6D, 0x65, 0x6E, 0x74, 0x40, 0x31,
0x3A, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3A, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x77, 0x2F, 0x66, 0x72, 0x61, 0x67, 0x6D, 0x65, 0x6E,
0x74, 0x40, 0x32, 0x3A, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x3A, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x5F, 0x5F, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x5F,
0x66, 0x69, 0x78, 0x75, 0x70, 0x73, 0x5F, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x66, 0x72, 0x61, 0x67, 0x6D, 0x65, 0x6E, 0x74, 0x40, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x5F, 0x5F, 0x6F, 0x76, 0x65, 0x72, 0x6C, 0x61, 0x79, 0x5F, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09,
0x63, 0x6F, 0x6D, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6C, 0x65, 0x00, 0x74, 0x61, 0x72, 0x67, 0x65,
0x74, 0x00, 0x73, 0x6D, 0x69, 0x5F, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x00, 0x73, 0x74, 0x61,
0x74, 0x75, 0x73, 0x00, 0x70, 0x69, 0x6E, 0x63, 0x74, 0x72, 0x6C, 0x2D, 0x6E, 0x61, 0x6D, 0x65,
0x73, 0x00, 0x70, 0x69, 0x6E, 0x63, 0x74, 0x72, 0x6C, 0x2D, 0x30, 0x00, 0x62, 0x72, 0x63, 0x6D,
0x2C, 0x70, 0x69, 0x6E, 0x73, 0x00, 0x62, 0x72, 0x63, 0x6D, 0x2C, 0x66, 0x75, 0x6E, 0x63, 0x74,
0x69, 0x6F, 0x6E, 0x00, 0x62, 0x72, 0x63, 0x6D, 0x2C, 0x70, 0x75, 0x6C, 0x6C, 0x00, 0x70, 0x68,
0x61, 0x6E, 0x64, 0x6C, 0x65, 0x00, 0x73, 0x6D, 0x69, 0x5F, 0x70, 0x69, 0x6E, 0x73, 0x00, 0x73,
0x6F, 0x63, 0x00, 0x73, 0x6D, 0x69, 0x00, 0x67, 0x70, 0x69, 0x6F, 0x00,
};
#ifdef __cplusplus
}
#endif
#endif // __cariboulite_dtbo_h__

Wyświetl plik

@ -1,10 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "CARIBOULITE Events"
#include "zf_log/zf_log.h"
#include "cariboulite.h"
#include "cariboulite_events.h"

Wyświetl plik

@ -1,19 +0,0 @@
#ifndef __CARIBOULITE_EVENTS_H__
#define __CARIBOULITE_EVENTS_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "caribou_smi/caribou_smi.h"
void caribou_smi_error_event(caribou_smi_channel_en channel, void* context);
void caribou_smi_rx_data_event(caribou_smi_channel_en channel, caribou_smi_sample_complex_int16 *cplx_vec, size_t num_samples_in_vec, void* context);
size_t caribou_smi_tx_data_event(caribou_smi_channel_en channel, caribou_smi_sample_complex_int16 *cplx_vec, size_t *num_samples_in_vec, void* context);
#ifdef __cplusplus
}
#endif
#endif // __CARIBOULITE_EVENTS_H__

Wyświetl plik

@ -1,115 +0,0 @@
#ifndef __CARIBOULITE_INT_H__
#define __CARIBOULITE_INT_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "cariboulite_config_default.h"
#include <signal.h>
#include <linux/limits.h> // for file system path max length
#include "hat/hat.h"
#include "io_utils/io_utils.h"
#include "io_utils/io_utils_spi.h"
#include "io_utils/io_utils_sys_info.h"
#include "rffc507x/rffc507x.h"
#include "at86rf215/at86rf215.h"
#include "caribou_programming/caribou_prog.h"
#include "caribou_fpga/caribou_fpga.h"
#include "caribou_smi/caribou_smi.h"
#include "cariboulite_radio.h"
// GENERAL SETTINGS
struct sys_st_t;
typedef void (*signal_handler)( struct sys_st_t *sys, // the current cariboulite low-level management struct
void* context, // custom context - can be a higher level app class
int signal_number, // the signal number
siginfo_t *si);
typedef enum
{
signal_handler_op_last = 0, // The curtom sighandler operates (if present) after the default sig handler
signal_handler_op_first = 1, // The curtom sighandler operates (if present) before the default sig handler
signal_handler_op_override = 2, // The curtom sighandler operates (if present) instead of the default sig handler
} signal_handler_operation_en;
typedef enum
{
system_type_unknown = 0,
system_type_cariboulite_full = 1,
system_type_cariboulite_ism = 2,
} system_type_en;
typedef enum
{
cariboulite_ext_ref_src_modem = 0,
cariboulite_ext_ref_src_connector = 1,
cariboulite_ext_ref_src_txco = 2,
cariboulite_ext_ref_src_na = 3, // not applicable
} cariboulite_ext_ref_src_en;
typedef enum
{
sys_status_unintialized = 0,
sys_status_minimal_init = 1,
sys_status_full_init = 2,
} sys_status_en;
typedef struct
{
cariboulite_ext_ref_src_en src;
double freq_hz;
} cariboulite_ext_ref_settings_st;
typedef struct sys_st_t
{
// board information
hat_board_info_st board_info;
system_type_en sys_type;
// SoC level
io_utils_spi_st spi_dev;
caribou_smi_st smi;
//ustimer_t timer;
// Peripheral chips
caribou_fpga_st fpga;
at86rf215_st modem;
cariboulite_ext_ref_settings_st ext_ref_settings;
rffc507x_st mixer;
// Configuration
int reset_fpga_on_startup;
int force_fpga_reprogramming;
int fpga_config_resistor_state;
char firmware_path_operational[PATH_MAX];
char firmware_path_testing[PATH_MAX];
// Radios
cariboulite_radio_state_st radio_low;
cariboulite_radio_state_st radio_high;
// Signals
signal_handler signal_cb;
void* singal_cb_context;
signal_handler_operation_en sig_op;
// Management
caribou_fpga_versions_st fpga_versions;
uint8_t fpga_error_status;
int fpga_config_res_state;
// Initialization
sys_status_en system_status;
} sys_st;
#ifdef __cplusplus
}
#endif
#endif // __CARIBOULITE_INT_H__

Wyświetl plik

@ -1,626 +0,0 @@
/**
* @file cariboulite_radio.h
* @author David Michaeli
* @date September 2023
* @brief System level radio API
*
* Radio device implementation exposing TxRx API
*/
#ifndef __CARIBOULABS_RADIO_H__
#define __CARIBOULABS_RADIO_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
/**
* @brief Radio channel direction
*/
typedef enum
{
cariboulite_channel_dir_rx = 0,
cariboulite_channel_dir_tx = 1,
} cariboulite_channel_dir_en;
typedef enum
{
cariboulite_channel_s1g = 0,
cariboulite_channel_hif = 1,
} cariboulite_channel_en;
typedef enum
{
cariboulite_ext_ref_off = 0,
cariboulite_ext_ref_26mhz = 26,
cariboulite_ext_ref_32mhz = 32,
} cariboulite_ext_ref_freq_en;
typedef enum
{
cariboulite_radio_cmd_nop = 0x0, // No operation (dummy)
cariboulite_radio_cmd_sleep = 0x1, // Go to sleep
cariboulite_radio_state_cmd_trx_off = 0x2, // Transceiver off, SPI active
cariboulite_radio_state_cmd_tx_prep = 0x3, // Transmit preparation
cariboulite_radio_state_cmd_tx = 0x4, // Transmit
cariboulite_radio_state_cmd_rx = 0x5, // Receive
cariboulite_radio_state_transition = 0x6, // State transition in progress
cariboulite_radio_state_cmd_reset = 0x7, // Transceiver is in state RESET or SLEEP
// if commanded reset, the transceiver state will
// automatically end up in state TRXOFF
} cariboulite_radio_state_cmd_en;
typedef enum
{
cariboulite_radio_rx_bw_200KHz = 0x0,
cariboulite_radio_rx_bw_250KHz = 0x1,
cariboulite_radio_rx_bw_312KHz = 0x2,
cariboulite_radio_rx_bw_400KHz = 0x3,
cariboulite_radio_rx_bw_500KHz = 0x4,
cariboulite_radio_rx_bw_625KHz = 0x5,
cariboulite_radio_rx_bw_787KHz = 0x6,
cariboulite_radio_rx_bw_1000KHz = 0x7,
cariboulite_radio_rx_bw_1250KHz = 0x8,
cariboulite_radio_rx_bw_1562KHz = 0x9,
cariboulite_radio_rx_bw_2000KHz = 0xA,
cariboulite_radio_rx_bw_2500KHz = 0xB,
} cariboulite_radio_rx_bw_en;
typedef enum
{
cariboulite_radio_rx_f_cut_0_25_half_fs = 0, // whan 4MSPS => 500 KHz
cariboulite_radio_rx_f_cut_0_375_half_fs = 1, // whan 4MSPS => 750 KHz
cariboulite_radio_rx_f_cut_0_5_half_fs = 2, // whan 4MSPS => 1000 KHz
cariboulite_radio_rx_f_cut_0_75_half_fs = 3, // whan 4MSPS => 1500 KHz
cariboulite_radio_rx_f_cut_half_fs = 4, // whan 4MSPS => 2000 KHz
} cariboulite_radio_f_cut_en;
typedef enum
{
cariboulite_radio_rx_sample_rate_4000khz = 0x1,
cariboulite_radio_rx_sample_rate_2000khz = 0x2,
cariboulite_radio_rx_sample_rate_1333khz = 0x3,
cariboulite_radio_rx_sample_rate_1000khz = 0x4,
cariboulite_radio_rx_sample_rate_800khz = 0x5,
cariboulite_radio_rx_sample_rate_666khz = 0x6,
cariboulite_radio_rx_sample_rate_500khz = 0x8,
cariboulite_radio_rx_sample_rate_400khz = 0xA,
} cariboulite_radio_sample_rate_en;
typedef enum
{
cariboulite_radio_tx_cut_off_80khz = 0x0,
cariboulite_radio_tx_cut_off_100khz = 0x1,
cariboulite_radio_tx_cut_off_125khz = 0x2,
cariboulite_radio_tx_cut_off_160khz = 0x3,
cariboulite_radio_tx_cut_off_200khz = 0x4,
cariboulite_radio_tx_cut_off_250khz = 0x5,
cariboulite_radio_tx_cut_off_315khz = 0x6,
cariboulite_radio_tx_cut_off_400khz = 0x7,
cariboulite_radio_tx_cut_off_500khz = 0x8,
cariboulite_radio_tx_cut_off_625khz = 0x9,
cariboulite_radio_tx_cut_off_800khz = 0xA,
cariboulite_radio_tx_cut_off_1000khz = 0xB,
} cariboulite_radio_tx_cut_off_en;
typedef struct __attribute__((__packed__))
{
uint8_t wake_up_por:1;
uint8_t trx_ready:1;
uint8_t energy_detection_complete:1;
uint8_t battery_low:1;
uint8_t trx_error:1;
uint8_t IQ_if_sync_fail:1;
uint8_t res :2;
} cariboulite_radio_irq_st;
typedef struct __attribute__((__packed__))
{
int16_t i; // LSB
int16_t q; // MSB
} cariboulite_sample_complex_int16;
typedef struct __attribute__((__packed__))
{
uint8_t sync;
} cariboulite_sample_meta;
// Frequency Ranges
#define CARIBOULITE_6G_MIN (1.0e6)
#define CARIBOULITE_6G_MAX (6000.0e6)
#define CARIBOULITE_MIN_LO (85.0e6)
#define CARIBOULITE_MAX_LO (4200.0e6)
#define CARIBOULITE_2G4_MIN (2385.0e6)
#define CARIBOULITE_2G4_MAX (2495.0e6)
#define CARIBOULITE_S1G_MIN1 (377.0e6)
#define CARIBOULITE_S1G_MAX1 (530.0e6)
#define CARIBOULITE_S1G_MIN2 (779.0e6)
#define CARIBOULITE_S1G_MAX2 (1020.0e6)
typedef enum
{
conversion_dir_none = 0,
conversion_dir_up = 1,
conversion_dir_down = 2,
} cariboulite_conversion_dir_en;
// Radio Struct
typedef struct
{
struct sys_st_t* sys;
cariboulite_channel_dir_en channel_direction;
cariboulite_channel_en type;
bool active;
bool cw_output;
bool lo_output;
// MODEM STATES
cariboulite_radio_state_cmd_en state;
cariboulite_radio_irq_st interrupts;
bool rx_agc_on;
int rx_gain_value_db;
cariboulite_radio_rx_bw_en rx_bw;
cariboulite_radio_f_cut_en rx_fcut;
cariboulite_radio_sample_rate_en rx_fs;
int tx_power;
cariboulite_radio_tx_cut_off_en tx_bw;
cariboulite_radio_f_cut_en tx_fcut;
cariboulite_radio_sample_rate_en tx_fs;
bool tx_loopback_anabled;
// at86rf215_radio_energy_detection_st rx_energy_detection;
float rx_energy_detection_value;
float rx_rssi;
// FREQUENCY
bool modem_pll_locked;
bool lo_pll_locked;
double lo_frequency;
double if_frequency;
double actual_rf_frequency;
double requested_rf_frequency;
double rf_frequency_error;
// SMI STREAMS
int smi_channel_id;
// OTHERS
uint8_t random_value;
float rx_thermal_noise_floor;
} cariboulite_radio_state_st;
/**
* @brief Initialize a radio device
*
* Initialize a radio device allocated and given by the user. The radio device
* is setup to a known state and the internal variables (in the struct) are initialized.
* Note: This function shouldn't normally be used by the end-user as the radio module
* is initialized by the "driver initializations sequence" in "cariboulite_setup.h"
* and is ready to be used as the driver loading finishes
*
* @param radio a pre-allocated radio state structure to initialize
* @param sys a pointer to the system environment containing the relevant
* low level drivers and init / close logic.
* @param type the type of the channel (6g, or s1g)
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_init(cariboulite_radio_state_st* radio, struct sys_st_t *sys, cariboulite_channel_en type);
/**
* @brief Disposing the radio device
*
* Remove and free the resources taken by the radio device. The system returns to
* its known state.
* Note: This function shouldn't normally be used by the end-user as the radio module
* is disposed by the "driver closing sequence" in "cariboulite_setup.h"
* and is supposed to be hidden
*
* @param radio a pre-allocated radio state structure
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_dispose(cariboulite_radio_state_st* radio);
/**
* @brief Synchronizing radio struture contents to the hardware actual state
*
* Reading all the relevant modem internal (hardware) states to update and synchronize
* the software state to them.
*
* @param radio a pre-allocated radio state structure
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_sync_information(cariboulite_radio_state_st* radio);
/**
* @brief Set modem's external refernece ferquency
*
* This ext reference is needed for the mixer to lock
*
* @param sys a pointer to the system environment containing the relevant
* low level drivers and init / close logic.
* @param ref the used reference source (none, 26MHz, 32MHz, etc.)
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_ext_ref (struct sys_st_t *sys, cariboulite_ext_ref_freq_en ref);
/**
* @brief Get modem chip state
*
* Getting the modem current state
*
* @param radio a pre-allocated radio state structure
* @param state the modem state (pre-allocated pointer), nullable if not needed
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_mod_state (cariboulite_radio_state_st* radio, cariboulite_radio_state_cmd_en *state);
/**
* @brief Get modem irq table
*
* Reading the IRQ states table of the modem
*
* @param radio a pre-allocated radio state structure
* @param irq_table a table of interrupts state of the modem (nullable if not needed)
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_mod_intertupts (cariboulite_radio_state_st* radio, cariboulite_radio_irq_st **irq_table);
/**
* @brief Modem Rx gain control (write)
*
* Setting the Rx gain properties of the modem
*
* @param radio a pre-allocated radio state structure
* @param rx_agc_on enable modem automatic gain control
* @param rx_gain_value_db if AGC is disabled, here we can set the gain manually
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_set_rx_gain_control(cariboulite_radio_state_st* radio,
bool rx_agc_on,
int rx_gain_value_db);
/**
* @brief Modem Rx gain control (read)
*
* Getting the Rx gain properties of the modem
*
* @param radio a pre-allocated radio state structure
* @param rx_agc_on modem automatic gain control enabled
* @param rx_gain_value_db when AGC is disabled this is the actual gain control
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_rx_gain_control(cariboulite_radio_state_st* radio,
bool *rx_agc_on,
int *rx_gain_value_db);
/**
* @brief Modem Rx gain capabilities
*
* Reading the modem possible gain limits on Rx
*
* @param radio a pre-allocated radio state structure
* @param rx_min_gain_value_db modem gain limit low [dB]
* @param rx_max_gain_value_db modem gain limit high [dB]
* @param rx_gain_value_resolution_db modem gain steps [dB]
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_rx_gain_limits(cariboulite_radio_state_st* radio,
int *rx_min_gain_value_db,
int *rx_max_gain_value_db,
int *rx_gain_value_resolution_db);
/**
* @brief Modem set RX analog bandwidth
*
* Setting the RX analog bandwidth
*
* @param radio a pre-allocated radio state structure
* @param rx_bw bandwidth value
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_set_rx_bandwidth(cariboulite_radio_state_st* radio,
cariboulite_radio_rx_bw_en rx_bw);
int cariboulite_radio_set_rx_bandwidth_flt(cariboulite_radio_state_st* radio, float bw_hz);
/**
* @brief Modem get RX analog bandwidth
*
* Getting the RX analog bandwidth
*
* @param radio a pre-allocated radio state structure
* @param rx_bw bandwidth value (pointer - pre-allocated), nullable if not needed
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_rx_bandwidth(cariboulite_radio_state_st* radio,
cariboulite_radio_rx_bw_en *rx_bw);
int cariboulite_radio_get_rx_bandwidth_flt(cariboulite_radio_state_st* radio, float* bw_hz);
/**
* @brief Modem set RX sample cut-off bandwidth
*
* Setting the RX channel sample cut-off bandwidth (digital)
*
* @param radio a pre-allocated radio state structure
* @param rx_sample_rate the used rx sample rate
* @param rx_cutoff digital bandwidth
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_set_rx_samp_cutoff(cariboulite_radio_state_st* radio,
cariboulite_radio_sample_rate_en rx_sample_rate,
cariboulite_radio_f_cut_en rx_cutoff);
int cariboulite_radio_set_rx_sample_rate_flt(cariboulite_radio_state_st* radio, float sample_rate_hz);
/**
* @brief Modem get RX sample cut-off bandwidth
*
* Getting the RX channel sample cut-off bandwidth (digital)
*
* @param radio a pre-allocated radio state structure
* @param rx_sample_rate the used rx sample rate (pointer - pre-allocated), nullable if not needed
* @param rx_cutoff digital bandwidth (pointer - pre-allocated), nullable if not needed
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_rx_samp_cutoff(cariboulite_radio_state_st* radio,
cariboulite_radio_sample_rate_en *rx_sample_rate,
cariboulite_radio_f_cut_en *rx_cutoff);
int cariboulite_radio_get_rx_sample_rate_flt(cariboulite_radio_state_st* radio, float *sample_rate_hz);
/**
* @brief Modem set TX power
*
* Setting the Modem's output TX power towards the RFFE
*
* @param radio a pre-allocated radio state structure
* @param tx_power_dbm The TX power in dBm
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_set_tx_power(cariboulite_radio_state_st* radio,
int tx_power_dbm);
/**
* @brief Modem get TX power
*
* Getting the Modem's output TX power towards the RFFE
*
* @param radio a pre-allocated radio state structure
* @param tx_power_dbm The TX power in dBm (pointer - pre-allocated), nullable if not needed
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_tx_power(cariboulite_radio_state_st* radio,
int *tx_power_dbm);
/**
* @brief Modem set Tx analog Bandwidth
*
* Setting the Modem's Tx analog bandwidth
*
* @param radio a pre-allocated radio state structure
* @param tx_bw bandwidth (according to enumeration)
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_set_tx_bandwidth(cariboulite_radio_state_st* radio,
cariboulite_radio_tx_cut_off_en tx_bw);
int cariboulite_radio_set_tx_bandwidth_flt(cariboulite_radio_state_st* radio, float tx_bw);
/**
* @brief Modem get Tx analog Bandwidth
*
* Getting the current modem's Tx analog bandwidth
*
* @param radio a pre-allocated radio state structure
* @param tx_bw bandwidth (according to enumeration) - pointer, pre-allocated or nullable if not needed
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_tx_bandwidth(cariboulite_radio_state_st* radio,
cariboulite_radio_tx_cut_off_en *tx_bw);
int cariboulite_radio_get_tx_bandwidth_flt(cariboulite_radio_state_st* radio, float *tx_bw);
/**
* @brief Modem set Tx digital bandwidth
*
* Setting the modem's Tx digital cut-off bandwidth
*
* @param radio a pre-allocated radio state structure
* @param tx_sample_rate Tx sample rate
* @param tx_cutoff digital cut-off bandwidth
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_set_tx_samp_cutoff(cariboulite_radio_state_st* radio,
cariboulite_radio_sample_rate_en tx_sample_rate,
cariboulite_radio_f_cut_en tx_cutoff);
int cariboulite_radio_set_tx_samp_cutoff_flt(cariboulite_radio_state_st* radio, float sample_rate_hz);
/**
* @brief Modem get Tx digital bandwidth
*
* Getting the current modem's Tx digital cut-off bandwidth
*
* @param radio a pre-allocated radio state structure
* @param tx_sample_rate Tx sample rate, pointer, pre-allocated or nullable if not needed
* @param tx_cutoff digital cut-off bandwidth, pointer, pre-allocated or nullable if not needed
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_tx_samp_cutoff(cariboulite_radio_state_st* radio,
cariboulite_radio_sample_rate_en *tx_sample_rate,
cariboulite_radio_f_cut_en *tx_cutoff);
int cariboulite_radio_get_tx_samp_cutoff_flt(cariboulite_radio_state_st* radio, float *sample_rate_hz);
/**
* @brief Modem get current RSSI
*
* Getting the current receive signal strength indication
*
* @param radio a pre-allocated radio state structure
* @param rssi_dbm the RSSI measurement in dBm
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_rssi(cariboulite_radio_state_st* radio, float *rssi_dbm);
/**
* @brief Modem get current Energy Detection Value
*
* Getting the Rx energy detection value
*
* @param radio a pre-allocated radio state structure
* @param energy_det_val the energy value measurement in dBm
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_energy_det(cariboulite_radio_state_st* radio, float *energy_det_val);
/**
* @brief Modem get a random value
*
* The modem has an internal true random noise generation capability. This function
* returnes the current stored value
*
* @param radio a pre-allocated radio state structure
* @param uint8_t random value, pointer, pre-allocated or nullable if not needed
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_rand_val(cariboulite_radio_state_st* radio, uint8_t *rnd);
/**
* @brief Wait for all PLLs to lock
*
* In the modem this function waits for a safe completion of frequency switch. Until
* the modem indicates that the frequency was correctly set, the frequency switch should
* not be takes as granted.
*
* @param radio a pre-allocated radio state structure
* @param retries number of retries (typically up ot 5)
* @return "0" = didn't lock during the period or "1" - locked successfully
*/
bool cariboulite_radio_wait_modem_lock(cariboulite_radio_state_st* radio, int retries);
bool cariboulite_radio_wait_mixer_lock(cariboulite_radio_state_st* radio, int retries);
/**
* @brief Set modem frequency
*
* Setting the current frequency of the modem. The resulting frequency
* may be slightly different according to the internal PLL granularity
* and the resulting frequency is written back to the given pointer.
* The user may set the "break before make" to stich off the activation
* bit (reset Rx or Tx) and change the frequency in a cold state
*
* @param radio a pre-allocated radio state structure
* @param break_before_make break the current activity and only then set the frequency
* @param freq the frequency in Hz, a pointer that carries the frequency to set and
* returns back the actual set frequency after the operation is done
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_set_frequency(cariboulite_radio_state_st* radio,
bool break_before_make,
double *freq);
/**
* @brief Get current actual frequency
*
* Returns the current modem frequecny (which can be slightly different
* for the one set by the "set frequency" function)
*
* @param radio a pre-allocated radio state structure
* @param freq the frequnecy in Hz, pointer, pre-allocated or nullable if not needed
* @param lo in case of the high band channel, the LO of the mixer (otherwise unused)
* @param i_f in case of the high band channel, this is the IF frequency (otherwise unused)
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_frequency(cariboulite_radio_state_st* radio,
double *freq, double *lo, double* i_f);
/**
* @brief Activate the channel in a certain state
*
* Activates the Tx / Rx channel according to the "dir" parameter (either Tx or Rx).
* If we want to de-activate the channel, "dir" doesn't matter
*
* @param radio a pre-allocated radio state structure
* @param dir The channel activation direction
* @param active either true for activation or false for deactivation
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_activate_channel(cariboulite_radio_state_st* radio,
cariboulite_channel_dir_en dir,
bool active);
/**
* @brief Set up a CW output upon activation
*
* When we set the CW output, whenever the channel will be activated in Tx
* direction, the modem shall output a CW signal instead of the regular sample
* output. The CW frequency will be according to the set frequnecy
*
* @param radio a pre-allocated radio state structure
* @param lo_out setting the LO frequency output directly from the mixer (if 6G)
* @param cw_out activate (true) or deactivate (false) CW - the source is the modem
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_set_cw_outputs(cariboulite_radio_state_st* radio,
bool lo_out, bool cw_out);
/**
* @brief Get the current CW output state
*
* Checks whether the CW signal output is on
*
* @param radio a pre-allocated radio state structure
* @param lo_out the LO frequency existence from the mixer
* @param cw_out activate (true) or deactivate (false), pointer, pre-allocated,
* nullable if not needed
* @return 0 = success, -1 = failure
*/
int cariboulite_radio_get_cw_outputs(cariboulite_radio_state_st* radio,
bool *lo_out, bool *cw_out);
/**
* @brief Read samples
*
* Read the SMI driver and push the samples into the specified buffer of samples.
* The number of samples to be read is "length". If needed, a pre-allocated metadata buffer
* can be transfered to the function. It will hold the sample-matching metadata such as sync
* bits.
*
* @param radio a pre-allocated radio state structure
* @param buffer a pre-allocated buffer of native samples (complex i/q int16)
* @param metadata a pre-allocated metadata buffer
* @param length the number of I/Q samples to read
* @return the number of samples read
*/
int cariboulite_radio_read_samples(cariboulite_radio_state_st* radio,
cariboulite_sample_complex_int16* buffer,
cariboulite_sample_meta* metadata,
size_t length);
/**
* @brief Write samples
*
* Write to the SMI driver a certain number of samples.
*
* @param radio a pre-allocated radio state structure
* @param buffer a pre-allocated buffer of native samples (complex i/q int16)
* @param length the number of I/Q samples to write
* @return the number of samples written
*/
int cariboulite_radio_write_samples(cariboulite_radio_state_st* radio,
cariboulite_sample_complex_int16* buffer,
size_t length);
/**
* @brief Get Native Chunk (MTU)
*
* Gets the SMI IO native chunk size (MTU) in units of samples (4 bytes each)
*
* @param radio a pre-allocated radio state structure
* @return the number of samples in an native sized chunk
*/
size_t cariboulite_radio_get_native_mtu_size_samples(cariboulite_radio_state_st* radio);
#ifdef __cplusplus
}
#endif
#endif // __CARIBOULABS_RADIO_H__

Wyświetl plik

@ -1,821 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "CARIBOULITE Setup"
#include "zf_log/zf_log.h"
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <dirent.h>
#include "cariboulite_setup.h"
#include "cariboulite_events.h"
#include "cariboulite_fpga_firmware.h"
// Global system object for signals
static sys_st* sigsys = NULL;
//=================================================================
static void print_siginfo(siginfo_t *si)
{
printf("Signal [%d] caught, with the following information: \n", si->si_signo);
printf(" signal errno = %d\n", si->si_errno);
printf(" signal process pid = %d\n", si->si_pid);
printf(" signal process uid = %d\n", (int)si->si_uid);
printf(" signal status = %d\n", si->si_status);
switch (si->si_code)
{
case SI_ASYNCIO: printf(" signal errno / async IO completed\n"); break;
case SI_KERNEL: printf(" signal errno / signal raised by kernel\n"); break;
case SI_MESGQ: printf(" signal errno / state change of POSIX message queue\n"); break;
case SI_QUEUE: printf(" signal errno / sigqueue sent a message\n"); break;
case SI_TIMER: printf(" signal errno / POSIX timer expiration\n"); break;
case SI_TKILL: printf(" signal errno / tkill / tgkill sent the signal\n"); break;
case SI_SIGIO: printf(" signal errno / queueing of SIGIO\n"); break;
case SI_USER: printf(" signal errno / send by user kill() or raise()\n"); break;
default: break;
}
if (si->si_signo == SIGBUS)
switch (si->si_code)
{
case BUS_ADRALN: printf(" signal errno / SIGNBUS / alignment error\n"); break;
case BUS_ADRERR: printf(" signal errno / SIGNBUS / invalid physical address error\n");break;
case BUS_OBJERR: printf(" signal errno / SIGNBUS / general hardware arror\n"); break;
default: break;
}
if (si->si_signo == SIGCHLD)
switch (si->si_code)
{
case CLD_CONTINUED: printf(" signal errno / SIGCHLD / child stopped but then resumed\n"); break;
case CLD_DUMPED: printf(" signal errno / SIGCHLD / child terminated abnormally\n"); break;
case CLD_EXITED: printf(" signal errno / SIGCHLD / child terminated normally by exit()\n"); break;
case CLD_KILLED: printf(" signal errno / SIGCHLD / child was killed\n"); break;
case CLD_STOPPED: printf(" signal errno / SIGCHLD / child stopped\n"); break;
case CLD_TRAPPED: printf(" signal errno / SIGCHLD / child hit a trap\n"); break;
default: break;
}
if (si->si_signo == SIGFPE)
switch (si->si_code)
{
case FPE_FLTDIV: printf(" signal errno / SIGFPE / division by zero\n"); break;
case FPE_FLTOVF: printf(" signal errno / SIGFPE / float operation resulted in an overflow\n"); break;
case FPE_FLTINV: printf(" signal errno / SIGFPE / invalid floating operation\n"); break;
case FPE_FLTRES: printf(" signal errno / SIGFPE / float operation with invalid or inaxect result\n"); break;
case FPE_FLTSUB: printf(" signal errno / SIGFPE / floating operation resulted in an out of range subscript\n"); break;
case FPE_FLTUND: printf(" signal errno / SIGFPE / float operation resulted in underflow\n"); break;
case FPE_INTDIV: printf(" signal errno / SIGFPE / integer operation - division by zero\n"); break;
case FPE_INTOVF: printf(" signal errno / SIGFPE / integet operation resulted in overflow\n"); break;
default: break;
}
if (si->si_signo == SIGILL)
switch (si->si_code)
{
case ILL_ILLADR: printf(" signal errno / SIGILL / process attemped to enter an illegal addressing mode\n"); break;
case ILL_ILLOPC: printf(" signal errno / SIGILL / process attemped to execute illegal opcode\n"); break;
case ILL_ILLOPN: printf(" signal errno / SIGILL / process attemped to execute illegal operand\n"); break;
case ILL_PRVOPC: printf(" signal errno / SIGILL / process attemped to execute privileged opcode\n"); break;
case ILL_PRVREG: printf(" signal errno / SIGILL / process attemped to execute privileged register\n"); break;
case ILL_ILLTRP: printf(" signal errno / SIGILL / process attemped to enter illegal trap\n"); break;
default: break;
}
if (si->si_signo == SIGPOLL)
switch (si->si_code)
{
case POLL_ERR: printf(" signal errno / SIGPOLL / poll i/o error occured\n"); break;
case POLL_HUP: printf(" signal errno / SIGPOLL / the device hungup othe socked disconnecte\n"); break;
case POLL_IN: printf(" signal errno / SIGPOLL / poll - device available for read\n"); break;
case POLL_MSG: printf(" signal errno / SIGPOLL / poll - message is available\n"); break;
case POLL_OUT: printf(" signal errno / SIGPOLL / poll - device available for writing\n"); break;
case POLL_PRI: printf(" signal errno / SIGPOLL / poll - high priority data available for read\n"); break;
default: break;
}
if (si->si_signo == SIGSEGV)
switch (si->si_code)
{
case SEGV_ACCERR: printf(" signal errno / SIGSEGV / the process access a valid region of memory in an invalid way - violated memory access permissions\n"); break;
case SEGV_MAPERR: printf(" signal errno / SIGSEGV / the process access invalid region of memory\n"); break;
default: break;
}
/*if (si->si_signo == SIGTRAP)
switch (si->si_code)
{
case TRAP_BRKPT: printf(" signal errno / SIGTRAP / the process hit a breakpoint\n"); break;
case TRAP_TRACE: printf(" signal errno / SIGTRAP / the process hit a trace trap\n"); break;
default: printf(" signal errno unknown!\n"); break;
}*/
}
//=======================================================================================
void cariboulite_sigaction_basehandler (int signo,
siginfo_t *si,
void *ucontext)
{
int run_first = 0;
int run_last = 0;
// store the errno
int internal_errno = errno;
if (sigsys->signal_cb)
{
switch(sigsys->sig_op)
{
case signal_handler_op_last: run_last = 1; break;
case signal_handler_op_first: run_first = 1; break;
case signal_handler_op_override:
default:
sigsys->signal_cb(sigsys, sigsys->singal_cb_context, signo, si);
return;
}
}
if (run_first)
{
sigsys->signal_cb(sigsys, sigsys->singal_cb_context, signo, si);
}
// The default operation
pid_t sender_pid = si->si_pid;
printf("CaribouLite: Signal [%d] received from pid=[%d]\n", signo, (int)sender_pid);
print_siginfo(si);
switch (signo)
{
case SIGHUP: printf("SIGHUP: Terminal went away!\n"); cariboulite_release_driver(sigsys); break;
case SIGINT: printf("SIGINT: interruption\n"); cariboulite_release_driver(sigsys); break;
case SIGQUIT: printf("SIGQUIT: user generated quit char\n"); cariboulite_release_driver(sigsys); break;
case SIGILL: printf("SIGILL: process tried to execute illegal instruction\n"); cariboulite_release_driver(sigsys); break;
case SIGABRT: printf("SIGABRT: sent by abort() command\n"); cariboulite_release_driver(sigsys); break;
case SIGBUS: printf("SIGBUS: hardware alignment error\n"); cariboulite_release_driver(sigsys); break;
case SIGFPE: printf("SIGFPE: arithmetic exception\n"); cariboulite_release_driver(sigsys); break;
case SIGKILL: printf("SIGKILL: upcatchable process termination\n"); cariboulite_release_driver(sigsys); break;
case SIGSEGV: printf("SIGSEGV: memory access violation\n"); cariboulite_release_driver(sigsys); break;
case SIGTERM: printf("SIGTERM: process termination\n"); cariboulite_release_driver(sigsys); break;
default: break;
}
//getchar();
if (run_last)
{
sigsys->signal_cb(sigsys, sigsys->singal_cb_context, signo, si);
}
errno = internal_errno;
exit(0);
}
//=================================================
static int cariboulite_setup_signals(sys_st *sys)
{
cariboulite_setup_signal_handler (sys, NULL, signal_handler_op_last, NULL);
int signals[] = {SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGBUS, SIGFPE, SIGSEGV, SIGTERM};
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigsys = sys;
sa.sa_sigaction = cariboulite_sigaction_basehandler;
sa.sa_flags |= SA_RESTART | SA_SIGINFO;
int nsigs = sizeof(signals)/sizeof(signals[0]);
for (int i = 0; i < nsigs; i++)
{
if(sigaction(signals[i], &sa, NULL) != 0)
{
ZF_LOGE("error sigaction() [%d] signal registration", signals[i]);
return -cariboulite_signal_registration_failed;
}
}
return 0;
}
//=======================================================================================
int cariboulite_setup_io (sys_st* sys)
{
ZF_LOGD("Setting up board I/Os");
if (io_utils_setup() < 0)
{
ZF_LOGE("Error setting up io_utils");
return -1;
}
if (io_utils_spi_init(&sys->spi_dev) < 0)
{
ZF_LOGE("Error setting up io_utils_spi");
io_utils_cleanup();
return -1;
}
// Setup the initial states for components reset and SS
// ICE40
io_utils_set_gpio_mode(sys->fpga.cs_pin, io_utils_alt_gpio_out);
io_utils_write_gpio(sys->fpga.cs_pin, 1);
// AT86RF215
io_utils_set_gpio_mode(sys->modem.cs_pin, io_utils_alt_gpio_out);
io_utils_write_gpio(sys->modem.cs_pin, 1);
io_utils_set_gpio_mode(sys->modem.reset_pin, io_utils_alt_gpio_out);
io_utils_write_gpio(sys->modem.reset_pin, 0);
io_utils_set_gpio_mode(sys->modem.irq_pin, io_utils_alt_gpio_in);
// RFFC5072
io_utils_set_gpio_mode(sys->mixer.cs_pin, io_utils_alt_gpio_out);
io_utils_write_gpio(sys->mixer.cs_pin, 1);
io_utils_set_gpio_mode(sys->mixer.reset_pin, io_utils_alt_gpio_out);
io_utils_write_gpio(sys->mixer.reset_pin, 0);
return 0;
}
//=======================================================================================
int cariboulite_release_io (sys_st* sys)
{
ZF_LOGD("Releasing board I/Os - closing SPI");
io_utils_spi_close(&sys->spi_dev);
ZF_LOGD("Releasing board I/Os - io_utils_cleanup");
io_utils_cleanup();
return 0;
}
//=======================================================================================
int cariboulite_configure_fpga (sys_st* sys, cariboulite_firmware_source_en src, char* fpga_bin_path)
{
int ret = 0;
switch (src)
{
case cariboulite_firmware_source_file:
ret = caribou_fpga_program_to_fpga_from_file(&sys->fpga, fpga_bin_path, sys->force_fpga_reprogramming);
break;
case cariboulite_firmware_source_blob:
ret = caribou_fpga_program_to_fpga(&sys->fpga, cariboulite_firmware, sizeof(cariboulite_firmware), sys->force_fpga_reprogramming);
break;
default:
ZF_LOGE("lattice ice40 configuration source is invalid");
ret = -1;
break;
}
caribou_smi_setup_ios(&sys->smi);
return ret;
}
//=======================================================================================
int cariboulite_init_submodules (sys_st* sys)
{
int res = 0;
ZF_LOGD("initializing submodules");
// SMI Init
//------------------------------------------------------
ZF_LOGD("INIT FPGA SMI communication");
res = caribou_smi_init(&sys->smi, &sys);
if (res < 0)
{
ZF_LOGE("Error setting up smi submodule");
goto cariboulite_init_submodules_fail;
}
// AT86RF215
//------------------------------------------------------
ZF_LOGD("INIT MODEM - AT86RF215");
res = at86rf215_init(&sys->modem, &sys->spi_dev);
if (res < 0)
{
ZF_LOGE("Error initializing modem 'at86rf215'");
goto cariboulite_init_submodules_fail;
}
// Configure modem
//------------------------------------------------------
ZF_LOGD("Configuring modem initial state");
at86rf215_setup_rf_irq(&sys->modem, 0, 1, at86rf215_drive_current_2ma);
at86rf215_radio_set_state(&sys->modem, at86rf215_rf_channel_900mhz, at86rf215_radio_state_cmd_trx_off);
at86rf215_radio_set_state(&sys->modem, at86rf215_rf_channel_2400mhz, at86rf215_radio_state_cmd_trx_off);
at86rf215_radio_irq_st int_mask = {
.wake_up_por = 1,
.trx_ready = 1,
.energy_detection_complete = 1,
.battery_low = 1,
.trx_error = 1,
.IQ_if_sync_fail = 1,
.res = 0,
};
at86rf215_radio_setup_interrupt_mask(&sys->modem, at86rf215_rf_channel_900mhz, &int_mask);
at86rf215_radio_setup_interrupt_mask(&sys->modem, at86rf215_rf_channel_2400mhz, &int_mask);
at86rf215_iq_interface_config_st modem_iq_config = {
.loopback_enable = 0,
.drv_strength = at86rf215_iq_drive_current_4ma,
.common_mode_voltage = at86rf215_iq_common_mode_v_ieee1596_1v2,
.tx_control_with_iq_if = false,
.radio09_mode = at86rf215_iq_if_mode,
.radio24_mode = at86rf215_iq_if_mode,
.clock_skew = at86rf215_iq_clock_data_skew_4_906ns,
};
at86rf215_setup_iq_if(&sys->modem, &modem_iq_config);
at86rf215_radio_external_ctrl_st ext_ctrl = {
.ext_lna_bypass_available = 0,
.agc_backoff = 0,
.analog_voltage_external = 0,
.analog_voltage_enable_in_off = 1,
.int_power_amplifier_voltage = 2,
.fe_pad_configuration = 1,
};
at86rf215_radio_setup_external_settings(&sys->modem, at86rf215_rf_channel_900mhz, &ext_ctrl);
at86rf215_radio_setup_external_settings(&sys->modem, at86rf215_rf_channel_2400mhz, &ext_ctrl);
switch (sys->board_info.numeric_product_id)
{
//---------------------------------------------------
case system_type_cariboulite_full:
ZF_LOGD("This board is a Full version CaribouLite - setting ext_ref: modem, 32MHz");
// by default the ext_ref for the mixer - from the modem, 32MHz
sys->ext_ref_settings.src = cariboulite_ext_ref_src_modem;
sys->ext_ref_settings.freq_hz = 32000000;
cariboulite_radio_ext_ref (sys, cariboulite_ext_ref_32mhz);
break;
//---------------------------------------------------
case system_type_cariboulite_ism:
ZF_LOGD("This board is a ISM version CaribouLite - setting ext_ref: OFF");
sys->ext_ref_settings.src = cariboulite_ext_ref_src_na;
sys->ext_ref_settings.freq_hz = 0;
cariboulite_radio_ext_ref (sys, cariboulite_ext_ref_off);
break;
//---------------------------------------------------
default:
ZF_LOGE("Unknown board type - we sheuldn't get here");
break;
}
// The mixer - only relevant to the full version
if (sys->board_info.numeric_product_id == system_type_cariboulite_full)
{
// RFFC5072
//------------------------------------------------------
ZF_LOGD("INIT MIXER - RFFC5072");
res = rffc507x_init(&sys->mixer, &sys->spi_dev);
if (res < 0)
{
ZF_LOGE("Error initializing mixer 'rffc5072'");
goto cariboulite_init_submodules_fail;
}
// Configure mixer
//------------------------------------------------------
//rffc507x_setup_reference_freq(&sys->mixer, 26e6);
rffc507x_calibrate(&sys->mixer);
}
// Print the SPI information
//io_utils_spi_print_setup(&sys->spi_dev);
// Initialize the two Radio High-Level devices
cariboulite_radio_init(&sys->radio_low, sys, cariboulite_channel_s1g);
cariboulite_radio_init(&sys->radio_high, sys, cariboulite_channel_hif);
cariboulite_radio_set_rx_samp_cutoff(&sys->radio_low, cariboulite_radio_rx_sample_rate_4000khz, cariboulite_radio_rx_f_cut_half_fs);
cariboulite_radio_set_tx_samp_cutoff(&sys->radio_low, cariboulite_radio_rx_sample_rate_4000khz, cariboulite_radio_rx_f_cut_half_fs);
cariboulite_radio_set_rx_bandwidth(&sys->radio_low, cariboulite_radio_rx_bw_2500KHz);
cariboulite_radio_set_tx_bandwidth(&sys->radio_low, cariboulite_radio_tx_cut_off_1000khz);
cariboulite_radio_set_rx_samp_cutoff(&sys->radio_high, cariboulite_radio_rx_sample_rate_4000khz, cariboulite_radio_rx_f_cut_half_fs);
cariboulite_radio_set_tx_samp_cutoff(&sys->radio_high, cariboulite_radio_rx_sample_rate_4000khz, cariboulite_radio_rx_f_cut_half_fs);
cariboulite_radio_set_rx_bandwidth(&sys->radio_high, cariboulite_radio_rx_bw_2500KHz);
cariboulite_radio_set_tx_bandwidth(&sys->radio_high, cariboulite_radio_tx_cut_off_1000khz);
cariboulite_radio_activate_channel(&sys->radio_low, cariboulite_channel_dir_rx, false);
cariboulite_radio_activate_channel(&sys->radio_high, cariboulite_channel_dir_rx, false);
cariboulite_radio_sync_information(&sys->radio_low);
cariboulite_radio_sync_information(&sys->radio_high);
ZF_LOGD("Cariboulite submodules successfully initialized");
return 0;
cariboulite_init_submodules_fail:
// release the resources
cariboulite_release_submodules(sys);
return -1;
}
//=======================================================================================
system_type_en cariboulite_get_system_type(sys_st* sys)
{
return sys->board_info.numeric_product_id;
}
//=======================================================================================
int cariboulite_release_submodules(sys_st* sys)
{
int res = 0;
if (sys->system_status == sys_status_full_init)
{
// Dispose high-level radio devices
cariboulite_radio_dispose(&sys->radio_low);
cariboulite_radio_dispose(&sys->radio_high);
// SMI Module
//------------------------------------------------------
ZF_LOGD("CLOSE SMI");
caribou_smi_close(&sys->smi);
usleep(10000);
// AT86RF215
//------------------------------------------------------
ZF_LOGD("CLOSE MODEM - AT86RF215");
at86rf215_stop_iq_radio_receive (&sys->modem, at86rf215_rf_channel_900mhz);
at86rf215_stop_iq_radio_receive (&sys->modem, at86rf215_rf_channel_2400mhz);
at86rf215_close(&sys->modem);
//------------------------------------------------------
// RFFC5072 only relevant to the full version
if (sys->board_info.numeric_product_id == system_type_cariboulite_full)
{
ZF_LOGD("CLOSE MIXER - RFFC5072");
rffc507x_release(&sys->mixer);
}
}
if (sys->system_status == sys_status_minimal_init)
{
// FPGA Module
//------------------------------------------------------
ZF_LOGD("CLOSE FPGA communication");
res = caribou_fpga_close(&sys->fpga);
if (res < 0)
{
ZF_LOGE("FPGA communication release failed (%d)", res);
return -1;
}
}
return 0;
}
//=======================================================================================
int cariboulite_self_test(sys_st* sys, cariboulite_self_test_result_st* res)
{
memset(res, 0, sizeof(cariboulite_self_test_result_st));
int error_occured = 0;
//------------------------------------------------------
ZF_LOGD("Testing modem communication and versions");
uint8_t modem_pn = 0;
modem_pn = at86rf215_print_version(&sys->modem);
if (modem_pn != 0x34 && modem_pn != 0x35)
{
ZF_LOGE("The assembled modem is not AT86RF215 / IQ variant (product number: 0x%02x)", modem_pn);
res->modem_fail = 1;
error_occured = 1;
}
//------------------------------------------------------
// Mixer only relevant to the full version
if (sys->board_info.numeric_product_id == system_type_cariboulite_full)
{
ZF_LOGD("Testing mixer communication and versions");
rffc507x_device_id_st dev_id;
rffc507x_readback_status(&sys->mixer, &dev_id, NULL);
if (dev_id.device_id != 0x1140 && dev_id.device_id != 0x11C0)
{
ZF_LOGE("The assembled mixer is not RFFC5071/2[A]");
res->mixer_fail = 1;
error_occured = 1;
}
}
// check and report problems
if (!error_occured)
{
ZF_LOGD("Self-test process finished successfully!");
return 0;
}
ZF_LOGE("Self-test process finished with errors");
return -1;
}
//=================================================
int cariboulite_init_system_production(sys_st *sys)
{
zf_log_set_output_level(ZF_LOG_VERBOSE);
ZF_LOGI("driver initializing");
if (sys->system_status != sys_status_unintialized)
{
ZF_LOGE("System is already initialized! returning");
return 0;
}
// signals
ZF_LOGI("Initializing signals");
if(cariboulite_setup_signals(sys) != 0)
{
ZF_LOGE("error signal list registration");
return -cariboulite_signal_registration_failed;
}
// IO
if (cariboulite_setup_io(sys) != 0)
{
return -cariboulite_io_setup_failed;
}
// FPGA Init and Programming
ZF_LOGD("Initializing FPGA");
if (caribou_fpga_init(&sys->fpga, &sys->spi_dev) < 0)
{
ZF_LOGE("FPGA communication init failed");
cariboulite_deinit_system_production(sys);
return -1;
}
// Initialize the two Radio High-Level devices
cariboulite_radio_init(&sys->radio_low, sys, cariboulite_channel_s1g);
cariboulite_radio_init(&sys->radio_high, sys, cariboulite_channel_hif);
return 0;
}
//=================================================
int cariboulite_deinit_system_production(sys_st *sys)
{
if (sys->sys_type == system_type_cariboulite_full)
{
ZF_LOGD("CLOSE MIXER - RFFC5072");
rffc507x_release(&sys->mixer);
}
caribou_fpga_close(&sys->fpga);
ZF_LOGI("Releasing board I/Os - closing SPI");
io_utils_spi_close(&sys->spi_dev);
ZF_LOGI("Releasing board I/Os - io_utils_cleanup");
io_utils_cleanup();
return 0;
}
//=================================================
int cariboulite_init_driver_minimal(sys_st *sys, hat_board_info_st *info, bool production)
{
ZF_LOGD("driver initializing");
if (sys->system_status != sys_status_unintialized)
{
ZF_LOGE("System is already initialized! returning");
return 0;
}
// LINUX SIGNALS
// --------------------------------------------------------------------
ZF_LOGD("Initializing signals");
if(cariboulite_setup_signals(sys) != 0)
{
ZF_LOGE("error signal list registration");
return -cariboulite_signal_registration_failed;
}
// DETECT BOARD FROM DEVICE-TREE OR EEPROM
// --------------------------------------------------------------------
if (hat_detect_board(&sys->board_info) == 0)
{
if (hat_detect_from_eeprom(&sys->board_info) != 1)
{
ZF_LOGE("Failed to detect the board in /proc/device-tree/hat - EEPROM needs to be configured.");
ZF_LOGE("Please run the cariboulite_prod application with sudo permissions...");
}
else
{
ZF_LOGE("Failed to detect the board in /proc/device-tree/hat, though EEPROM is configured. Please reboot system...");
}
return -cariboulite_board_detection_failed;
}
sys->sys_type = (system_type_en)sys->board_info.numeric_product_id;
// CONFIGURE I/O
// --------------------------------------------------------------------
if (cariboulite_setup_io(sys) != 0)
{
return -cariboulite_io_setup_failed;
}
// FPGA Init and Programming
ZF_LOGD("Initializing FPGA");
if (caribou_fpga_init(&sys->fpga, &sys->spi_dev) < 0)
{
ZF_LOGE("FPGA communication init failed");
cariboulite_release_io (sys);
return -cariboulite_fpga_configuration_failed;
}
ZF_LOGD("Programming FPGA");
if (cariboulite_configure_fpga (sys, cariboulite_firmware_source_blob, NULL/*sys->firmware_path_operational*/) < 0)
{
ZF_LOGE("FPGA programming failed");
caribou_fpga_close(&sys->fpga);
cariboulite_release_io (sys);
return -cariboulite_fpga_configuration_failed;
}
if (sys->reset_fpga_on_startup)
{
//caribou_fpga_soft_reset(&sys->fpga);
}
// Reading the configuration from the FPGA (resistor set)
int led0 = 0, led1 = 0, btn = 0, cfg = 0;
caribou_fpga_get_io_ctrl_dig (&sys->fpga, &led0, &led1, &btn, &cfg);
ZF_LOGD("FPGA Digital Values: led0: %d, led1: %d, btn: %d, CFG[0..3]: [%d,%d,%d,%d]",
led0, led1, btn, (cfg >> 0) & 0x1, (cfg >> 1) & 0x1, (cfg >> 2) & 0x1, (cfg >> 3) & 0x1);
sys->fpga_config_resistor_state = cfg;
// if we are in the production phase, don't check hat configurations
if (production)
{
sys->system_status = sys_status_minimal_init;
return cariboulite_ok;
}
ZF_LOGD("Detected Board Information:");
cariboulite_print_board_info(sys, true);
// if the board info is requested by caller, copy it
if (info) memcpy(info, &sys->board_info, sizeof(hat_board_info_st));
sys->system_status = sys_status_minimal_init;
return cariboulite_ok;
}
//=================================================
void cariboulite_set_log_level(cariboulite_log_level_en lvl)
{
if (lvl == cariboulite_log_level_verbose)
{
zf_log_set_output_level(ZF_LOG_VERBOSE);
}
else if (lvl == cariboulite_log_level_info)
{
zf_log_set_output_level(ZF_LOG_INFO);
}
else if (lvl == cariboulite_log_level_none)
{
zf_log_set_output_level(ZF_LOG_ERROR);
}
}
//=================================================
int cariboulite_init_driver(sys_st *sys, hat_board_info_st *info)
{
int ret = cariboulite_init_driver_minimal(sys, info, false);
if (ret < 0)
{
return ret;
}
if (sys->system_status == sys_status_full_init)
{
ZF_LOGE("System is already fully initialized!");
return 0;
}
// INIT other sub-modules
if (cariboulite_init_submodules (sys) != 0)
{
caribou_fpga_close(&sys->fpga);
cariboulite_release_io (sys);
return -cariboulite_submodules_init_failed;
}
// Self-Test
cariboulite_self_test_result_st self_tes_res = {0};
if (cariboulite_self_test(sys, &self_tes_res) != 0)
{
caribou_fpga_close(&sys->fpga);
cariboulite_release_io (sys);
return -cariboulite_self_test_failed;
}
sys->system_status = sys_status_full_init;
return cariboulite_ok;
}
//=================================================
int cariboulite_setup_signal_handler (sys_st *sys,
signal_handler handler,
signal_handler_operation_en op,
void *context)
{
ZF_LOGD("setting up signal handler");
sys->signal_cb = handler;
sys->singal_cb_context = context;
sys->sig_op = op;
return 0;
}
//=================================================
void cariboulite_release_driver(sys_st *sys)
{
ZF_LOGD("driver being released");
if (sys->system_status != sys_status_unintialized)
{
//caribou_fpga_set_io_ctrl_mode (&sys->fpga, false, ...);
cariboulite_release_submodules(sys);
cariboulite_release_io (sys);
sys->system_status = sys_status_unintialized;
}
ZF_LOGD("driver released");
}
//=================================================
int cariboulite_get_serial_number(sys_st *sys, uint32_t* serial_number, int *count)
{
if (serial_number) *serial_number = sys->board_info.numeric_serial_number;
if (count) *count = 1;
return 0;
}
//=================================================
void cariboulite_lib_version(cariboulite_lib_version_st* v)
{
v->major_version = CARIBOULITE_MAJOR_VERSION;
v->minor_version = CARIBOULITE_MINOR_VERSION;
v->revision = CARIBOULITE_REVISION;
}
//===========================================================
int cariboulite_detect_board(sys_st *sys)
{
if (hat_detect_board(&sys->board_info) == 0)
{
// the board was not configured as a hat. Lets try and detect it directly
// through its EEPROM
if (hat_detect_from_eeprom(&sys->board_info) == 0)
{
return 0;
}
}
sys->sys_type = (system_type_en)sys->board_info.numeric_product_id;
return 1;
}
//===========================================================
void cariboulite_print_board_info(sys_st *sys, bool log)
{
hat_print_board_info(&sys->board_info, log);
if (log)
{
switch (sys->sys_type)
{
case system_type_cariboulite_full: ZF_LOGD("# Board Info - Product Type: CaribouLite FULL"); break;
case system_type_cariboulite_ism: ZF_LOGD("# Board Info - Product Type: CaribouLite ISM"); break;
case system_type_unknown:
default: ZF_LOGD("# Board Info - Product Type: Unknown"); break;
}
}
else
{
switch (sys->sys_type)
{
case system_type_cariboulite_full: printf(" Product Type: CaribouLite FULL"); break;
case system_type_cariboulite_ism: printf(" Product Type: CaribouLite ISM"); break;
case system_type_unknown:
default: printf(" Product Type: Unknown"); break;
}
}
}
//===========================================================
cariboulite_radio_state_st* cariboulite_get_radio_handle(sys_st* sys, cariboulite_channel_en type)
{
if (type == cariboulite_channel_s1g) return &sys->radio_low;
else if (type == cariboulite_channel_hif) return &sys->radio_high;
return NULL;
}

Wyświetl plik

@ -1,280 +0,0 @@
/**
* @file cariboulite_setup.h
* @author David Michaeli
* @date March 2023
* @brief System level setup functionality
*
* High level fucntionality - initialization, de-initialization,
* drivers loading, FPGA programming etc.
*/
#ifndef __CARIBOULITE_SETUP_H__
#define __CARIBOULITE_SETUP_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "cariboulite.h"
#include "cariboulite_internal.h"
#include "cariboulite_radio.h"
#include "caribou_fpga/caribou_fpga.h"
#include "at86rf215/at86rf215.h"
#include "rffc507x/rffc507x.h"
#include "caribou_smi/caribou_smi.h"
#include "io_utils/io_utils.h"
#include "io_utils/io_utils_spi.h"
#include "io_utils/io_utils_sys_info.h"
#include "cariboulite_config_default.h"
#define CARIBOULITE_MAJOR_VERSION 1
#define CARIBOULITE_MINOR_VERSION 2
#define CARIBOULITE_REVISION 0
typedef struct
{
int fpga_fail;
int modem_fail;
int mixer_fail;
int smi_fail;
} cariboulite_self_test_result_st;
/**
* @brief FPGA programming source definition
*
* While programming the FPGA, using "cariboulite_configure_fpga", it
* expects to receive the FGPA binary file to program either as a
* binary file full path or by a memory allocated buffer blob.
*/
typedef enum
{
cariboulite_firmware_source_file = 0,
cariboulite_firmware_source_blob = 1,
} cariboulite_firmware_source_en;
typedef enum
{
cariboulite_ok = 0,
cariboulite_board_detection_failed = 1,
cariboulite_io_setup_failed = 2,
cariboulite_fpga_configuration_failed = 3,
cariboulite_submodules_init_failed = 4,
cariboulite_self_test_failed = 5,
cariboulite_board_dependent_config_failed = 6,
cariboulite_signal_registration_failed = 7,
} cariboulite_errors_en;
/**
* @brief Detects the connected board and returns the detection result
*
* When a fully configures board is mounted, it is being pre-detected by the
* Linux HAT configuration during startup. Then this information is written as
* a "device-tree"-hat sysfs configuration. This configuration can be found in
* '/proc/device-tree/hat/...' files. They populate the system type, version,
* type and other attributes. This function tries to read these attributes to determine
* the type of system that is connected. If it doesn't find the system, it tries to
* further query it directrly through its i2c interface (EEPROM device on board).
* If all these doesn't work - it fails.
*
* @param sys a pre-allocated device handle structure
* @return success (1) or failure (0)
*/
int cariboulite_detect_board(sys_st *sys);
/**
* @brief Printing detected board information
*
* Once the detection succeeded, this function can print the device
* information within the HAT interface.
*
* @param sys a pre-allocated device handle structure
* @param log if true - print out the information on as log entries. Otherwise print
* it as a stdout (printf) output.
*/
void cariboulite_print_board_info(sys_st *sys, bool log);
/**
* @brief Setting global logging level
*
* options: cariboulite_log_level_verbose, cariboulite_log_level_info, cariboulite_log_level_none
*/
void cariboulite_set_log_level(cariboulite_log_level_en lvl);
/**
* @brief Fully initialize the system
*
* This function performs fully entry initialization of the system and
* a short self-test sequence to communication and check all the components
* respond.
*
* @param sys a pre-allocated device handle structure
* @param info the initialization performs internally the board detection sequence.
* which is stored into the "sys" struct. If the user wants to receive the
* information explicitely, he can pass here a pre-allocated info structure and
* it will be filled with the board information. If this is not needed
* user can pass "NULL"
* @return success / fail codes according to "cariboulite_errors_en"
*/
int cariboulite_init_driver(sys_st *sys, hat_board_info_st *info);
/**
* @brief Partially initialize the system
*
* Partial initialization of the system (low level drivers only) without the
* SDR functionality. This is mainly used for production where we want only to program the
* FPGA and test the system at its low level.
*
* @param sys a pre-allocated device handle structure
* @param info the initialization performs internally the board detection sequence.
* which is stored into the "sys" struct. If the user wants to receive the
* information explicitely, he can pass here a pre-allocated info structure and
* it will be filled with the board information. If this is not needed
* user can pass "NULL"
* @return success / fail codes according to "cariboulite_errors_en"
*/
int cariboulite_init_driver_minimal(sys_st *sys, hat_board_info_st *info, bool production);
int cariboulite_init_system_production(sys_st *sys);
int cariboulite_deinit_system_production(sys_st *sys);
/**
* @brief Register an explicit linux signal handler in the application level
*
* If a linux signal occures it is caught by the system. The user may want to be
* notified on the signal in the app level. This is done by registering a handler
* function with this fucntion.
*
* @param sys a pre-allocated device handle structure
* @param handler a handler function with the following prototype:
* void (*signal_handler)( struct sys_st_t *sys, // the current cariboulite low-level management struct
* void* context, // custom context - can be a higher level app class
* int signal_number, // the signal number
* siginfo_t *si);
* @param op determines when the handler is shot:
* signal_handler_op_last => The custom sighandler operates (if present) after the default sig handler
* signal_handler_op_first => The custom sighandler operates (if present) before the default sig handler
* signal_handler_op_override => The custom sighandler operates (if present) instead of the default sig handler
* @param context this void* pointer may contain an app specific handle to be passed to the explicit signal handler.
* @return always 0 (success)
*/
int cariboulite_setup_signal_handler (sys_st *sys,
signal_handler handler,
signal_handler_operation_en op,
void *context);
/**
* @brief Program and configure the FPGA
*
* Programming the FPGA using either an external binary file (.bin) or
* an image of the file within the local memory (a buffer).
*
* @param sys a pre-allocated device handle structure
* @param src the source of the binary file. In case of the "blob" choise,
* the binary file is stored inside an array named "cariboulite_fpga_firmware"
* which is automatically generated after FPGA binary is created. This
* buffer is located inside a file named "cariboulite_fpga_firmware.h"
* @param fpga_bin_path the path of the binary file - only applicable if
* "cariboulite_firmware_source_file" was chosen as the "src". otherwise
* NULL should be passed here.
* @return 0 (success), -1 (fail)
*/
int cariboulite_configure_fpga (sys_st* sys, cariboulite_firmware_source_en src, char* fpga_bin_path);
/**
* @brief Release resources
*
* Releasing resources taken during init and program execution. Should be
* called at the end of the session.
*
* @param sys a pre-allocated device handle structure
*/
void cariboulite_release_driver(sys_st *sys);
/**
* @brief Get current API lib version
*
* @param v a struct containing the version information
*/
void cariboulite_lib_version(cariboulite_lib_version_st* v);
/**
* @brief Get board serial number
*
* Note - this 32bit serial number is a digest value of the UUID 128 bit that
* is automatically generated for each board. It is basically the result of
* "xor" operations on the UUID's parts.
*
* @param sys a pre-allocated device handle structure
* @param serial_number a 32bit storage to store the serial number (can be NULL - if not needed)
* @param count the number of 32bit variables returned - always returns as "1".
* @return always 0
*/
int cariboulite_get_serial_number(sys_st *sys, uint32_t* serial_number, int *count);
/**
* @brief Initilize IOs
*
* This is a sub-part of the initialization sequence and it
* initializes only the IOs (GPIOs, interfaces) of the RPI
*
* @param sys a pre-allocated device handle structure
* @return 0 (sucess), -1 (fail)
*/
int cariboulite_setup_io (sys_st* sys);
/**
* @brief Release IOs
*
* Giving back the IOs and returning them to their default state
*
* @param sys a pre-allocated device handle structure
* @return 0 (sucess), -1 (fail)
*/
int cariboulite_release_io (sys_st* sys);
int cariboulite_init_submodules (sys_st* sys);
int cariboulite_release_submodules(sys_st* sys);
/**
* @brief Component communication test
*
* Self testing communication with components, their versions, etc.
*
* @param sys a pre-allocated device handle structure
* @param res test-result
* @return 0 (sucess), -1 (fail)
*/
int cariboulite_self_test(sys_st* sys, cariboulite_self_test_result_st* res);
/**
* @brief Getting the used radio handle
*
* After initializing the drivers, a radio device is created and stored in
* the device driver main struct. To manipulate the radio features, this radio
* handle (pointer) needs to be obtained by the user. This handle is normally
* passed to the radio manipulation functions in "cariboulite_radio.h"
*
* @param sys a pre-allocated device handle structure
* @param res test-result
* @return 0 (sucess), -1 (fail)
*/
cariboulite_radio_state_st* cariboulite_get_radio_handle(sys_st* sys, cariboulite_channel_en type);
/**
* @brief Getting CaribouLite Type
*
* Returns the version of the hardware - ISM / 6G / Unknown
* ISM has two channels - 900MHz and 2.4 GHz
* 6G has two channels - 900MHz and 6000MHz
*
* @return according to cariboulite_version_en
*/
system_type_en cariboulite_get_system_type(sys_st* sys);
#ifdef __cplusplus
}
#endif
#endif // __CARIBOULITE_SETUP_H__

Wyświetl plik

@ -1,95 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "CARIBOULITE Test"
#include "zf_log/zf_log.h"
#include <sys/types.h>
#include <unistd.h>
#include "cariboulite_setup.h"
#include "cariboulite_events.h"
#include "cariboulite.h"
#include "hat/hat.h"
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
struct sigaction act;
int program_running = 1;
int signal_shown = 0;
CARIBOULITE_CONFIG_DEFAULT(cariboulite_sys);
int app_menu(sys_st* sys);
//=================================================
int stop_program ()
{
if (program_running) ZF_LOGD("program termination requested");
program_running = 0;
return 0;
}
//=================================================
void sighandler( struct sys_st_t *sys,
void* context,
int signal_number,
siginfo_t *si)
{
if (signal_shown != signal_number)
{
ZF_LOGI("Received signal %d", signal_number);
signal_shown = signal_number;
}
switch (signal_number)
{
case SIGINT:
case SIGTERM:
case SIGABRT:
case SIGILL:
case SIGSEGV:
case SIGFPE: stop_program(); break;
default: return; break;
}
}
//=================================================
int main(int argc, char *argv[])
{
// init the program
cariboulite_sys.force_fpga_reprogramming = 0;
if (cariboulite_init_driver(&cariboulite_sys, NULL)!=0)
{
ZF_LOGE("driver init failed, terminating...");
return -1;
}
// setup the signal handler
cariboulite_setup_signal_handler (&cariboulite_sys, sighandler, signal_handler_op_last, &cariboulite_sys);
sleep(1);
while (program_running)
{
int ret = app_menu(&cariboulite_sys);
if (ret < 0)
{
ZF_LOGE("Error occurred, terminating...");
break;
}
else if (ret == 0)
{
ZF_LOGI("Quit command => terminating...");
break;
}
}
// close the driver and release resources
cariboulite_release_driver(&cariboulite_sys);
return 0;
}

Wyświetl plik

@ -1,366 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "CARIBOULITE Main"
#include "zf_log/zf_log.h"
#include <sys/types.h>
#include <unistd.h>
#include "cariboulite_setup.h"
#include "cariboulite_events.h"
#include "cariboulite.h"
#include "hat/hat.h"
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
//=======================================================================
// INTERNAL VARIABLES AND DEFINITIONS
static struct sigaction act;
static int signal_shown = 0;
CARIBOULITE_CONFIG_STATIC_DEFAULT(cariboulite_sys);
// Program state structure
typedef struct
{
// Arguments
char *filename;
int rx_channel;
double frequency;
float gain;
float ppm_error;
size_t samples_to_read;
int force_fpga_prog;
int write_metadata;
// State
int sample_infinite;
int program_running;
int sys_type;
size_t native_read_len;
cariboulite_sample_complex_int16* buffer;
cariboulite_sample_meta* metadata;
cariboulite_radio_state_st *radio;
FILE *file;
} prog_state_st;
static prog_state_st state = {0};
//=================================================
static int stop_program (void)
{
if (state.program_running) ZF_LOGD("program termination requested");
state.program_running = 0;
return 0;
}
//=================================================
static void sighandler(void* context,
int signal_number,
siginfo_t *si)
{
struct sys_st_t *s = (struct sys_st_t *)context;
if (signal_shown != signal_number)
{
ZF_LOGI("Received signal %d", signal_number);
signal_shown = signal_number;
}
switch (signal_number)
{
case SIGINT:
case SIGTERM:
case SIGABRT:
case SIGILL:
case SIGSEGV:
case SIGFPE: stop_program(); break;
default: return; break;
}
}
//=================================================
static void init_program_state(void)
{
state.filename = NULL;
state.rx_channel = 0; // low freq channel
state.frequency = 915e6;
state.gain = 0;
state.ppm_error = 0;
state.samples_to_read = 1024*1024/8;
state.force_fpga_prog = 0;
state.write_metadata = 0;
// state
state.sample_infinite = 1;
state.program_running = 1;
state.sys_type = system_type_cariboulite_ism;
state.native_read_len = 1024 * 1024 / 8;
state.buffer = NULL;
state.metadata = NULL;
state.radio = NULL;
state.file = NULL;
}
//=======================================================================
static void usage(void)
{
fprintf(stderr,
"CaribouLite I/Q recorder\n\n"
"Usage:\t-c the RX channel to use (0: low, 1: high)\n"
"\t-f frequency [Hz]\n"
"\t[-g gain (default: -1 for agc)]\n"
"\t[-p ppm_error (default: 0)]\n"
"\t[-n number of samples to read (default: 0, infinite)]\n"
"\t[-S force sync output (default: async)]\n"
"\t[-F force fpga reprogramming (default: '0')]\n"
"\t[-M write metadata (default: '0')]\n"
"\tfilename ('-' dumps samples to stdout)\n\n"
"Example:\n"
"\t1. Sample S1G channel at 905MHz into filename capture.bin\n"
"\t\tcariboulite_util -c 0 -f 905000000 capture.bin\n"
"\t2. Sample S1G channel at 905MHz into filename capture.bin, only 30000 samples\n"
"\t\tcariboulite_util -c 0 -f 905000000 -n 30000 capture.bin\n\n");
exit(1);
}
//=======================================================================
static int check_inputs(void)
{
state.sys_type = cariboulite_sys.board_info.numeric_product_id;
if (state.rx_channel != 0 && state.rx_channel != 1)
{
ZF_LOGE("Radio selection incompatible [%d] (should be either '0' or '1')", state.rx_channel);
return -1;
}
if (state.rx_channel == 0 &&
(state.frequency < CARIBOULITE_S1G_MIN1 || state.frequency > CARIBOULITE_S1G_MAX2 ||
(state.frequency > CARIBOULITE_S1G_MAX1 && state.frequency < CARIBOULITE_S1G_MIN2)) )
{
ZF_LOGE("S1G radio frequency (%.2f) is out of the [%.0f .. %.0f, %.0f .. %.0f] MHz range", state.frequency,
CARIBOULITE_S1G_MIN1/1e6, CARIBOULITE_S1G_MAX1/1e6, CARIBOULITE_S1G_MIN2/1e6, CARIBOULITE_S1G_MAX2/1e6);
return -1;
}
if (state.rx_channel == 1 && state.sys_type == system_type_cariboulite_full &&
(state.frequency < CARIBOULITE_6G_MIN && state.frequency > CARIBOULITE_6G_MAX))
{
ZF_LOGE("HiF (full) radio frequency (%.2f) is out of the [%.0f .. %.0f] MHz range", state.frequency,
CARIBOULITE_6G_MIN/1e6, CARIBOULITE_6G_MAX/1e6);
return -1;
}
if (state.rx_channel == 1 && state.sys_type == system_type_cariboulite_ism &&
(state.frequency < CARIBOULITE_2G4_MIN && state.frequency > CARIBOULITE_2G4_MAX))
{
ZF_LOGE("HiF (ISM) radio frequency (%.2f) is out of the [%.0f .. %.0f] MHz range", state.frequency,
CARIBOULITE_2G4_MIN/1e6, CARIBOULITE_2G4_MAX/1e6);
return -1;
}
if ((state.gain < 0 || state.gain > 23.0*3.0) && state.gain != -1)
{
ZF_LOGE("Rx channel gain %.0f is incompatible (legal range: [%.0f .. %.0f] dB", state.gain,
0.0, 23.0*3.0);
return -1;
}
return 0;
}
//=================================================
int analyze_arguments(int argc, char *argv[])
{
int opt;
while ((opt = getopt(argc, argv, "c:f:g:n:S:F")) != -1) {
switch (opt) {
case 'c':
state.rx_channel = (int)atoi(optarg);
printf("DBG: RX Channel = %d\n", state.rx_channel);
break;
case 'f':
state.frequency = atof(optarg);
printf("DBG: Frequency = %.1f Hz\n", state.frequency);
break;
case 'g':
state.gain = (int)(atof(optarg));
if (state.gain == -1)
{
printf("DBG: Rx Gain = AGC\n");
}
else
{
printf("DBG: Rx Gain = %.1f dB\n", state.gain);
}
break;
case 'p':
state.ppm_error = atof(optarg);
printf("DBG: PPM Error = %.2f\n", state.ppm_error);
break;
case 'n':
state.samples_to_read = atoi(optarg);
state.sample_infinite = state.samples_to_read > 0 ? 0 : 1;
if (state.sample_infinite) printf("DBG: Infinite Read\n");
else printf("DBG: Number of samples: %lu\n", state.samples_to_read);
break;
case 'F':
state.force_fpga_prog = 1;
printf("DBG: Force FPGA programming = %d\n", state.force_fpga_prog);
break;
case 'M':
state.write_metadata = 1;
printf("DBG: Write metadata = %d\n", state.write_metadata);
break;
default:
usage();
return -1;
break;
}
}
if (argc <= optind)
{
usage();
return -1;
}
else state.filename = argv[optind];
return 0;
}
//=================================================
void release_system(void)
{
cariboulite_radio_activate_channel(state.radio, cariboulite_channel_dir_rx, false);
if (state.buffer) free (state.buffer);
if (state.metadata) free (state.metadata);
if (strcmp(state.filename, "-") != 0)
{
if (state.file) fclose(state.file);
}
cariboulite_close();
}
//=================================================
int main(int argc, char *argv[])
{
// pre-init the program state
//-------------------------------------
init_program_state();
// Analyze program opts
//-------------------------------------
if (analyze_arguments(argc, argv) != 0)
{
return 0;
}
// Init the program
//-------------------------------------
if (cariboulite_init(state.force_fpga_prog, cariboulite_log_level_none) != 0)
{
ZF_LOGE("driver init failed, terminating...");
return -1;
}
// setup the signal handler
cariboulite_register_signal_handler ( sighandler, &cariboulite_sys);
// check the input arguments (done after init to identify system type)
if (check_inputs() != 0)
{
cariboulite_close();
return -1;
}
// get the correct radio from the possible two
state.radio = cariboulite_get_radio((cariboulite_channel_en)(state.rx_channel));
// Allocate rx buffer and metadata
state.native_read_len = cariboulite_radio_get_native_mtu_size_samples(state.radio);
state.buffer = malloc(sizeof(cariboulite_sample_complex_int16)*state.native_read_len);
if (state.buffer == NULL)
{
ZF_LOGE("RX Buffer allocation failed");
release_system();
return -1;
}
state.metadata = malloc(sizeof(cariboulite_sample_meta)*state.native_read_len);
if (state.metadata == NULL)
{
ZF_LOGE("Metadata allocation failed");
release_system();
return -1;
}
// Align the length (only if it is >0)
if (!state.sample_infinite)
{
state.samples_to_read = ((state.samples_to_read % state.native_read_len) == 0) ?
(state.samples_to_read) :
(state.samples_to_read / state.native_read_len + 1) * state.native_read_len;
}
// Init the radio
//-------------------------------------
// Set radio parameters
cariboulite_radio_set_frequency(state.radio, true, &state.frequency);
cariboulite_radio_set_rx_gain_control(state.radio, state.gain == -1.0, state.gain);
cariboulite_radio_sync_information(state.radio);
cariboulite_radio_activate_channel(state.radio, cariboulite_channel_dir_rx, true);
// Open the file for writing
if(strcmp(state.filename, "-") == 0)
{
state.file = stdout;
}
else
{
state.file = fopen(state.filename, "wb");
if (!state.file)
{
ZF_LOGE("Failed to open %s", state.filename);
release_system();
return -1;
}
}
usleep(100000);
while (state.program_running)
{
int ret = cariboulite_radio_read_samples(state.radio, state.buffer, state.metadata, state.native_read_len);
if (ret < 0)
{
ZF_LOGE("Samples read operation failed. Quiting...");
continue;
}
// TODO: how should the metadata be expressed in the file?
int wret = fwrite(state.buffer, 1, ret*4, state.file);
if (wret != (ret*4))
{
ZF_LOGE("Writing into file failed, exiting!\n");
break;
}
if (!state.sample_infinite)
{
state.samples_to_read -= ret;
if (state.samples_to_read <= 0)
break;
}
}
// close the driver and release resources
cariboulite_close();
return 0;
}

Wyświetl plik

@ -1,2 +0,0 @@
# build directories
build

Wyświetl plik

@ -1,30 +0,0 @@
cmake_minimum_required(VERSION 3.15)
project(cariboulite)
set(CMAKE_BUILD_TYPE Release)
#Bring the headers, such as Student.h into the project
set(SUPER_DIR ${PROJECT_SOURCE_DIR}/..)
include_directories(/.)
include_directories(${SUPER_DIR})
#However, the file(GLOB...) allows for wildcard additions:
set(SOURCES_LIB tsqueue.c tiny_list.c circular_buffer.cpp entropy.c)
#add_compile_options(-Wall -Wextra -pedantic -Werror)
add_compile_options(-Wall -Wextra -pedantic -Wno-missing-braces)
#Generate the static library from the sources
add_library(datatypes STATIC ${SOURCES_LIB})
target_include_directories(datatypes PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
#add_executable(test_tsqueue test_tsqueue.c)
#target_link_libraries(test_tsqueue datatypes pthread)
#add_executable(test_circular_buffer test_circular_buffer.cpp)
#target_link_libraries(test_circular_buffer datatypes pthread)
add_executable(test_tiny_list test_tiny_list.c)
target_link_libraries(test_tiny_list datatypes pthread)
#Set the location for library installation -- i.e., /usr/lib in this case
# not really necessary in this example. Use "sudo make install" to apply
install(TARGETS datatypes DESTINATION /usr/lib)

Wyświetl plik

@ -1 +0,0 @@
#include "circular_buffer.h"

Wyświetl plik

@ -1,165 +0,0 @@
#ifndef __CIRC_BUFFER_H__
#define __CIRC_BUFFER_H__
#include <string.h>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <atomic>
#define IS_POWER_OF_2(x) (!((x) == 0) && !((x) & ((x) - 1)))
#define MIN(x,y) ((x)>(y)?(y):(x))
template <class T>
class circular_buffer {
public:
circular_buffer(size_t size, bool override_write = true, bool block_read = true)
{
max_size_ = size;
if (!IS_POWER_OF_2(max_size_))
{
max_size_ = next_power_of_2(max_size_);
}
buf_ = new T[max_size_];
override_write_ = override_write;
block_read_ = block_read;
}
~circular_buffer()
{
std::unique_lock<std::mutex> lock(mutex_);
delete []buf_;
}
size_t put(const T *data, size_t length)
{
std::lock_guard<std::mutex> lock(mutex_);
if ((max_size_ - size()) < length && override_write_)
{
// pop the amount of data the is needed
tail_ += length - (max_size_ - size());
}
size_t len = MIN(length, max_size_ - head_ + tail_);
auto l = MIN(len, max_size_ - (head_ & (max_size_ - 1)));
memcpy(buf_ + (head_ & (max_size_ - 1)), data, l * sizeof(T));
memcpy(buf_, data + l, (len - l) * sizeof(T));
head_ += len;
if (block_read_)
{
cond_var_.notify_one();
}
return len;
}
size_t get(T *data, size_t length, int timeout_us = 100000)
{
std::unique_lock<std::mutex> lock(mutex_);
if (block_read_)
{
cond_var_.wait_for(lock, std::chrono::microseconds(timeout_us), [&]()
{
// Acquire the lock only if
// we got enough items
return size() >= length;
});
if (size() < length)
{
return 0;
}
}
size_t len = MIN(length, head_ - tail_);
auto l = MIN(len, max_size_ - (tail_ & (max_size_ - 1)));
if (data != NULL)
{
memcpy(data, buf_ + (tail_ & (max_size_ - 1)), l * sizeof(T));
memcpy(data + l, buf_, (len - l) * sizeof(T));
}
tail_ += len;
return len;
}
void put(T item)
{
put(&item, 1);
}
T get()
{
T item;
get(&item, 1);
return item;
}
void reset()
{
std::unique_lock<std::mutex> lock(mutex_);
head_ = tail_ = 0;
}
inline bool empty()
{
return head_ == tail_;
}
inline bool full()
{
return size() == capacity();
}
inline size_t capacity() const
{
return max_size_;
}
size_t size()
{
return (head_ - tail_);
}
void print_buffer()
{
std::unique_lock<std::mutex> lock(mutex_);
size_t t = tail_;
int i = 0;
while (t < head_)
{
printf("%d => %d\n", i++, (int)buf_[t++&(max_size_-1)]);
}
}
private:
uint32_t next_power_of_2 (uint32_t x)
{
uint32_t power = 1;
while(power < x)
{
power <<= 1;
}
return power;
}
private:
std::mutex mutex_;
std::condition_variable cond_var_;
T* buf_;
size_t head_ = 0;
size_t tail_ = 0;
size_t max_size_;
bool override_write_;
bool block_read_;
};
#endif

Wyświetl plik

@ -1,57 +0,0 @@
#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "ENTROPY"
#include "zf_log/zf_log.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <linux/random.h>
#include <sys/ioctl.h>
#include "entropy.h"
typedef struct {
int bit_count; /* number of bits of entropy in data */
int byte_count; /* number of bytes of data in array */
unsigned char buf[1];
} entropy_t;
//=====================================================
int add_entropy(uint8_t byte)
{
int rand_fid = open("/dev/urandom", O_RDWR);
if (rand_fid != 0)
{
// error opening device
ZF_LOGE("Opening /dev/urandom device file failed");
return -1;
}
entropy_t ent =
{
.bit_count = 8,
.byte_count = 1,
.buf = {byte},
};
if (ioctl(rand_fid, RNDADDENTROPY, &ent) != 0)
{
ZF_LOGE("IOCTL to /dev/urandom device file failed");
}
if (close(rand_fid) !=0 )
{
ZF_LOGE("Closing /dev/urandom device file failed");
return -1;
}
return 0;
}

Wyświetl plik

@ -1,18 +0,0 @@
#ifndef __ENTROPY_H__
#define __ENTROPY_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
int add_entropy(uint8_t byte);
#ifdef __cplusplus
}
#endif
#endif // __ENTROPY_H__

Wyświetl plik

@ -1,55 +0,0 @@
#include "circular_buffer.h"
#include <unistd.h>
#include <stdio.h>
circular_buffer<uint32_t> *buf = NULL;
uint32_t data1[100] = {0};
uint32_t data2[100] = {0};
void producer(int times)
{
while (true)
{
sleep(0);
printf("THREAD! PUT1 100, ret %lu\n", buf->put(data1, 100));
sleep(0);
printf("PUT1 60, ret %lu\n", buf->put(data1, 60));
}
}
void consumer(int times)
{
printf("Capacity = %lu\n", buf->capacity());
while (true)
{
printf("GET1 100, ret %lu\n", buf->get(data2, 100));
printf("GET1 100, ret %lu\n", buf->get(data2, 100));
printf("GET1 100, ret %lu\n", buf->get(data2, 100));
printf("GET1 100, ret %lu\n", buf->get(data2, 60));
}
printf("finished\n");
}
int main ()
{
for (int i = 0; i < 100; i++)
{
data1[i] = i;
data2[i] = i*i;
}
buf = new circular_buffer<uint32_t>(200, true, true);
int times = 1;
std::thread t1(producer, times);
std::thread t2(consumer, times);
t2.join();
t1.join();
delete buf;
return 0;
}

Wyświetl plik

@ -1,27 +0,0 @@
#include <stdio.h>
#include "tiny_list.h"
#include "tiny_queue.h"
int a = 0;
tiny_queue_st queue;
int main ()
{
tiny_queue_init (&queue);
tiny_queue_enqueue (queue, &a, sizeof (a)); a++;
tiny_queue_enqueue (queue, &a, sizeof (a)); a++;
tiny_queue_enqueue (queue, &a, sizeof (a)); a++;
tiny_list_print (queue);
tiny_queue_dequeue (queue, &a, NULL);
tiny_list_print (queue);
tiny_queue_dequeue (queue, &a, NULL);
tiny_list_print (queue);
tiny_queue_dequeue (queue, &a, NULL);
tiny_list_print (queue);
tiny_queue_free (queue);
}

Wyświetl plik

@ -1,112 +0,0 @@
#include <stdio.h>
#include <unistd.h>
#include "tsqueue.h"
tsqueue_st q = {0};
pthread_t tid;
pthread_attr_t attr;
#define RAND_DIVISOR 1000000000
// Producer Thread
void *producer(void *param)
{
int item = 0;
while(1)
{
// sleep for a random period of time
/*int rNum = rand() / RAND_DIVISOR;
sleep(rNum);
*/
//getchar();
// generate a random number
//item = rand();
item ++;
int res = tsqueue_insert_push_buffer(&q, (uint8_t*)&item, sizeof(item), 0, 200, 1);
if (res != 0)
{
if (res == TSQUEUE_NOT_INITIALIZED) fprintf(stderr, "Queue not inited\n");
if (res == TSQUEUE_FAILED_FULL) fprintf(stderr, "Queue is full!\n");
if (res == TSQUEUE_SEM_FAILED) fprintf(stderr, "Push semaphore failed\n");
if (res == TSQUEUE_TIMEOUT) fprintf(stderr, "Push TIMEOUT\n");
}
else
{
printf("producer produced and pushed %d\n", item);
}
}
}
// Consumer Thread
void *consumer(void *param)
{
tsqueue_item_st* item = NULL;
int i = 0;
while(1)
{
/* sleep for a random period of time */
//int rNum = rand() / RAND_DIVISOR;
//sleep(1);
//getchar();
int res;
if (i==0) res = tsqueue_pop_item(&q, &item, 200);
else res = tsqueue_peek_item(&q, &item, 200);
if (i==0) printf("POP ==> ");
else printf("PEEK ==> ");
if (res != 0)
{
if (res == TSQUEUE_NOT_INITIALIZED) fprintf(stderr, "Queue not inited\n");
if (res == TSQUEUE_SEM_FAILED) fprintf(stderr, "Pop semaphore failed\n");
if (res == TSQUEUE_FAILED_EMPTY) fprintf(stderr, "Pop failed - Empty!!\n");
if (res == TSQUEUE_TIMEOUT) fprintf(stderr, "Pop TIMEOUT\n");
}
else
{
int val = *((uint32_t*)item->data);
printf("consumer consumed %d\n", val);
}
i = !i;
}
}
// Main
int main(int argc, char *argv[])
{
int res = 0;
if(argc != 4)
{
fprintf(stderr, "USAGE:./main.out <INT> <INT> <INT>\n");
return 1;
}
int mainSleepTime = atoi(argv[1]); /* Time in seconds for main to sleep */
int numProd = atoi(argv[2]); /* Number of producer threads */
int numCons = atoi(argv[3]); /* Number of consumer threads */
res = tsqueue_init(&q, 4, 4);
// Create the producer threads
for(int i = 0; i < numProd; i++)
{
pthread_create(&tid, &attr, producer,NULL);
}
// Create the consumer threads
for(int i = 0; i < numCons; i++)
{
pthread_create(&tid, &attr, consumer,NULL);
}
sleep(mainSleepTime);
printf("Exit the program\n");
res = tsqueue_release(&q);
return 0;
}

Wyświetl plik

@ -1,278 +0,0 @@
#include <stdio.h>
#include <pthread.h>
#include "tiny_list.h"
//============================================================
int tiny_list_init (tiny_list_st** list)
{
tiny_list_st* new_list = (tiny_list_st*)malloc(sizeof (tiny_list_st));
if (new_list == NULL)
{
printf("'tiny_list_init' - allocation failed\n");
return -1;
}
if (pthread_mutex_init(&new_list->mtx, NULL) != 0)
{
printf("'tiny_list_init' - mutex initialization failed\n");
free (new_list);
return -1;
}
pthread_mutex_unlock (&new_list->mtx);
new_list->head = NULL;
new_list->tail = NULL;
new_list->num_of_elements = 0;
*list = new_list;
return 0;
}
//============================================================
void tiny_list_free (tiny_list_st* list)
{
tiny_list_remove_all (list);
free (list);
}
//============================================================
int tiny_list_add (tiny_list_st* list, void* data, unsigned int len, tiny_list_pos_en pos)
{
if (list == NULL)
{
printf("'tiny_list_add' - list not initialized\n");
return -1;
}
tiny_list_node_st* new_node = tiny_list_create_node (data, len);
if (new_node == NULL)
{
printf("'tiny_list_add' - node creation failed\n");
return -1;
}
pthread_mutex_lock (&list->mtx);
if (pos == pos_head)
{
new_node->next = list->head;
new_node->last = NULL;
list->head = new_node;
if (new_node->next) new_node->next->last = new_node;
if (list->num_of_elements == 0) list->tail = list->head;
}
else // default = tail
{
new_node->next = NULL;
new_node->last = list->tail;
list->tail = new_node;
if (new_node->last) new_node->last->next = new_node;
if (list->num_of_elements == 0) list->head = list->tail;
}
list->num_of_elements ++;
pthread_mutex_unlock (&list->mtx);
return 0;
}
//============================================================
int tiny_list_remove (tiny_list_st* list, void* data, unsigned int *len, tiny_list_pos_en pos)
{
tiny_list_node_st* node = NULL;
if (list == NULL)
{
printf("'tiny_list_remove' - list not initialized\n");
return -1;
}
pthread_mutex_lock (&list->mtx);
if (list->num_of_elements == 0)
{
printf("'tiny_list_remove' - the list is empty - nothing to remove\n");
pthread_mutex_unlock (&list->mtx);
return -1;
}
if (pos == pos_head)
{
node = list->head;
list->head = node->next;
if (list->head) list->head->last = NULL;
}
else // default = tail
{
node = list->tail;
list->tail = node->last;
if (list->tail) list->tail->next = NULL;
}
list->num_of_elements --;
if (list->num_of_elements == 0)
{
list->tail = NULL;
list->head = NULL;
}
pthread_mutex_unlock (&list->mtx);
if (len) *len = node->len;
if (data) memcpy(data, node->data, node->len);
tiny_list_destroy_node (node);
return 0;
}
//============================================================
void tiny_list_remove_all (tiny_list_st* list)
{
tiny_list_node_st* node = NULL;
if (list == NULL)
{
printf("'tiny_list_free' - trying to free not initialized list\n");
return;
}
node = list->head;
pthread_mutex_unlock (&list->mtx);
pthread_mutex_destroy (&list->mtx);
while (node != NULL)
{
node = tiny_list_destroy_node (node);
}
list->num_of_elements = 0;
list->head = NULL;
list->tail = NULL;
}
//============================================================
int tiny_list_peek (tiny_list_st* list, void* data, unsigned int *len, tiny_list_pos_en pos)
{
tiny_list_node_st* node = NULL;
if (list == NULL)
{
printf("'tiny_list_peek' - list not initialized\n");
return -1;
}
pthread_mutex_lock (&list->mtx);
if (list->num_of_elements == 0)
{
printf("'tiny_list_remove' - the list is empty - nothing to peek\n");
pthread_mutex_unlock (&list->mtx);
return -1;
}
if (pos == pos_head)
{
node = list->head;
}
else // default = tail
{
node = list->tail;
}
if (len) *len = node->len;
if (data) memcpy(data, node->data, node->len);
pthread_mutex_unlock (&list->mtx);
return 0;
}
//============================================================
int tiny_list_num_elements (tiny_list_st* list)
{
int num;
if (list == NULL)
{
printf("'tiny_list_num_elements' - list not initialized\n");
return -1;
}
pthread_mutex_lock (&list->mtx);
num = list->num_of_elements;
pthread_mutex_unlock (&list->mtx);
return num;
}
//============================================================
void tiny_list_print (tiny_list_st* list)
{
tiny_list_node_st* cur_node;
if (list == NULL)
{
printf("'tiny_list_print' - list is not initialized\n");
return;
}
pthread_mutex_lock (&list->mtx);
printf("Number of elements: %d - \n", list->num_of_elements);
cur_node = list->head;
while (cur_node)
{
tiny_list_print_node (cur_node);
cur_node = cur_node->next;
}
pthread_mutex_unlock (&list->mtx);
}
//============================================================
tiny_list_node_st* tiny_list_create_node (void *data, unsigned int len)
{
tiny_list_node_st* new_node = (tiny_list_node_st*)malloc (sizeof (tiny_list_node_st));
if (new_node == NULL)
{
return NULL;
}
new_node->data = malloc (len);
if (new_node->data == NULL)
{
free (new_node);
return NULL;
}
memcpy (new_node->data, data, len);
new_node->len = len;
new_node->next = NULL;
new_node->last = NULL;
return new_node;
}
//============================================================
tiny_list_node_st* tiny_list_destroy_node (tiny_list_node_st* node)
{
tiny_list_node_st* temp = NULL;
if (node == NULL)
{
return NULL;
}
temp = node->next;
free (node->data);
node->len = 0;
node->next = NULL;
node->last = NULL;
free (node);
return temp;
}
//============================================================
void tiny_list_print_node (tiny_list_node_st* node)
{
if (node == NULL)
{
printf("empty node\n");
return;
}
printf(" PTR ADDR: %08lX, FIRST BYTE: %02X, LEN: %d\n", (long)(node->data), ((unsigned char*)(node->data))[0], node->len);
}

Wyświetl plik

@ -1,56 +0,0 @@
#ifndef __TINY_LIST_H__
#define __TINY_LIST_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
typedef enum
{
pos_head = 0,
pos_tail = 1,
} tiny_list_pos_en;
struct tiny_list_node_t
{
void* data;
unsigned int len;
struct tiny_list_node_t *last;
struct tiny_list_node_t *next;
};
typedef struct tiny_list_node_t tiny_list_node_st;
typedef struct
{
pthread_mutex_t mtx;
struct tiny_list_node_t* head;
struct tiny_list_node_t* tail;
unsigned int num_of_elements;
} tiny_list_st;
int tiny_list_init (tiny_list_st** list);
void tiny_list_free (tiny_list_st* list);
int tiny_list_add (tiny_list_st* list, void* data, unsigned int len, tiny_list_pos_en pos);
int tiny_list_remove (tiny_list_st* list, void* data, unsigned int *len, tiny_list_pos_en pos);
void tiny_list_remove_all (tiny_list_st* list);
int tiny_list_peek (tiny_list_st* list, void* data, unsigned int *len, tiny_list_pos_en pos);
int tiny_list_num_elements (tiny_list_st* list);
void tiny_list_print (tiny_list_st* list);
tiny_list_node_st* tiny_list_create_node (void *data, unsigned int len);
tiny_list_node_st* tiny_list_destroy_node (tiny_list_node_st* node);
void tiny_list_print_node (tiny_list_node_st* node);
#ifdef __cplusplus
}
#endif
#endif //__TINY_LIST_H__

Wyświetl plik

@ -1,25 +0,0 @@
#ifndef __TINY_QUEUE_H__
#define __TINY_QUEUE_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include "tiny_list.h"
typedef tiny_list_st* tiny_queue_st;
#define tiny_queue_init(q_ptr) (tiny_list_init(q_ptr))
#define tiny_queue_free(q) (tiny_list_free(q))
#define tiny_queue_enqueue(q,d_array,l) (tiny_list_add((q),(d_array),(l),pos_head))
#define tiny_queue_dequeue(q,d_array,l_ptr) (tiny_list_remove((q),(d_array),(l_ptr),pos_tail))
#define tiny_queue_is_empty(q) (tiny_list_num_elements(q)==0)
#define tiny_queue_num_elements(q) (tiny_list_num_elements(q))
#define tiny_queue_empty(q) (tiny_list_remove_all (q))
#ifdef __cplusplus
}
#endif
#endif //__TINY_QUEUE_H__

Wyświetl plik

@ -1,24 +0,0 @@
#ifndef __TINY_STACK_H__
#define __TINY_STACK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include "tiny_list.h"
typedef tiny_list_st* tiny_stack_st;
#define tiny_stack_init(s_ptr) (tiny_list_init(s_ptr))
#define tiny_stack_free(s) (tiny_list_free(s))
#define tiny_stack_enqueue(s,d_array,l) (tiny_list_add((s),(d_array),(l),pos_head))
#define tiny_stack_dequeue(s,d_array,l_ptr) (tiny_list_remove((s),(d_array),(l_ptr),pos_head))
#define tiny_stack_is_empty(s) (tiny_list_num_elements(s)==0)
#define tiny_stack_empty(s) (tiny_list_remove_all (s))
#ifdef __cplusplus
}
#endif
#endif //__TINY_STACK_H__

Wyświetl plik

@ -1,309 +0,0 @@
#include "tsqueue.h"
#include <string.h>
#include <errno.h>
#include <time.h>
//=======================================================================
int tsqueue_init(tsqueue_st* q, int item_size_bytes, int total_element_count)
{
if (q == NULL) return -1;
if (item_size_bytes == 0 || total_element_count == 0) return -2;
q->max_num_items = total_element_count;
q->item_size_bytes = item_size_bytes;
q->sema_inited = 0;
if (pthread_mutex_init(&q->mutex, NULL) != 0)
{
//printf("tsqueue1\n");
return TSQUEUE_MUTEX_INIT_FAILED;
}
if (sem_init(&q->full, 0, 0) != 0)
{
//printf("tsqueue2\n");
pthread_mutex_destroy(&q->mutex);
return TSQUEUE_MUTEX_INIT_FAILED;
}
if (sem_init(&q->empty, 0, total_element_count) != 0)
{
//printf("tsqueue3\n");
sem_destroy(&q->full);
pthread_mutex_destroy(&q->mutex);
return TSQUEUE_SEM_INIT_FAILED;
}
q->sema_inited = 1;
q->items = (tsqueue_item_st*)malloc(total_element_count*sizeof(tsqueue_item_st));
if (q->items == NULL)
{
//printf("tsqueue4\n");
return TSQUEUE_MEM_ALLOC_FAILED;
}
memset (q->items, 0, total_element_count*sizeof(tsqueue_item_st));
for (int i = 0; i < total_element_count; i++)
{
q->items[i].metadata = 0;
q->items[i].data = (uint8_t*)malloc(q->item_size_bytes);
if (q->items[i].data == NULL)
{
//printf("tsqueue5 %d\n", i);
tsqueue_release(q);
return TSQUEUE_MEM_ALLOC_FAILED;
}
q->items[i].length = 0;
}
q->current_num_of_items = 0;
q->head = 0;
q->tail = 0;
q->num_items_dropped = 0;
return TSQUEUE_OK;
}
//=======================================================================
int tsqueue_release(tsqueue_st* q)
{
if (q == NULL) return -1;
for (int i = 0; i < q->max_num_items; i++)
{
if (q->items[i].data != NULL) free (q->items[i].data);
}
free(q->items);
if (q->sema_inited)
{
sem_destroy(&q->empty);
sem_destroy(&q->full);
pthread_mutex_destroy(&q->mutex);
}
return TSQUEUE_OK;
}
//=======================================================================
int tsqueue_insert_push_item(tsqueue_st* q, tsqueue_item_st* item, int timeout_us, int override)
{
return tsqueue_insert_push_buffer(q, item->data, item->length, item->metadata, timeout_us, override);
}
//=======================================================================
void tsqueue_add_ms_to_timespec(struct timespec *ts, int us)
{
long int sec = ts->tv_sec;
long int nsec = ts->tv_nsec;
long int added_ns = us * 1000L;
nsec += added_ns;
int added_sec = nsec / 1000000000L;
sec += added_sec;
nsec -= added_sec * 1000000000L;
ts->tv_nsec = nsec;
ts->tv_sec = sec;
}
//=======================================================================
int tsqueue_wait_on_sem(sem_t* sem, int timeout_us)
{
// check if timeout is needed
if (timeout_us <= 0)
{
int s = 0;
while ((s = sem_wait(sem)) == -1 && errno == EINTR) continue;
if (s == -1) return TSQUEUE_SEM_FAILED;
}
else
{
struct timespec ts = {0};
int s = 0;
// get current time
clock_gettime(CLOCK_REALTIME, &ts);
tsqueue_add_ms_to_timespec(&ts, timeout_us);
while ((s = sem_timedwait(sem, &ts)) == -1 && errno == EINTR)
{
continue; /* Restart if interrupted by handler. */
}
// Check what happened - it was not an interruption
if (s == -1)
{
if (errno == ETIMEDOUT)
{
return TSQUEUE_TIMEOUT;
}
else
{
return TSQUEUE_SEM_FAILED;
}
}
}
return 0;
}
//=======================================================================
int tsqueue_insert_push_buffer(tsqueue_st* q, uint8_t* buffer, int length, uint32_t metadata, int timeout_us, int override)
{
int error = 0;
if (q == NULL) return TSQUEUE_NOT_INITIALIZED;
if (!override)
{
// wait until empty rises => someone poped an item thus some place was
// freed for a new item. immediatelly after catching the event, decrease empty (notice it is full)
// in the case of override - no waiting is needed
int res = tsqueue_wait_on_sem(&q->empty, timeout_us);
if (res < 0) return res;
}
// acquire the mutex lock
pthread_mutex_lock(&q->mutex);
// insert the item
// When the buffer is not full add the item and increment the counter
if(q->current_num_of_items < q->max_num_items)
{
int data_size = length;
q->items[q->head].metadata = metadata;
if (data_size > q->item_size_bytes)
{
printf("Incorrect item data size\n");
data_size = q->item_size_bytes;
}
memcpy (q->items[q->head].data, buffer, data_size);
q->items[q->head].length = data_size;
q->head ++;
if (q->head >= q->max_num_items) q->head = 0;
q->current_num_of_items ++;
}
else if (override)
{
int res = tsqueue_wait_on_sem(&q->full, timeout_us);
if (res < 0) return res;
int data_size = length;
q->items[q->head].metadata = metadata;
if (data_size > q->item_size_bytes)
{
printf("Incorrect item data size\n");
data_size = q->item_size_bytes;
}
memcpy (q->items[q->head].data, buffer, data_size);
q->items[q->head].length = data_size;
q->head ++;
if (q->head >= q->max_num_items) q->head = 0;
q->tail ++;
if (q->tail >= q->max_num_items) q->tail = 0;
}
else
{
error = TSQUEUE_FAILED_FULL;
}
// release the mutex lock
pthread_mutex_unlock(&q->mutex);
// signal full
sem_post(&q->full);
return error;
}
//=======================================================================
int tsqueue_peek_item(tsqueue_st* q, tsqueue_item_st** item, int timeout_us)
{
int error = 0;
if (q == NULL) return TSQUEUE_NOT_INITIALIZED;
int res = tsqueue_wait_on_sem(&q->full, timeout_us);
if (res < 0) return res;
// aquire the mutex lock
pthread_mutex_lock(&q->mutex);
// pop the item
if(q->current_num_of_items > 0)
{
*item = &q->items[q->tail];
}
else
{
error = TSQUEUE_FAILED_EMPTY;
}
// release the mutex lock
pthread_mutex_unlock(&q->mutex);
// signal full to note that we didn't pop the item
sem_post(&q->full);
return error;
}
//=======================================================================
int tsqueue_pop_item(tsqueue_st* q, tsqueue_item_st** item, int timeout_us)
{
int error = 0;
if (q == NULL) return TSQUEUE_NOT_INITIALIZED;
int res = tsqueue_wait_on_sem(&q->full, timeout_us);
if (res < 0) return res;
// aquire the mutex lock
pthread_mutex_lock(&q->mutex);
// pop the item
if(q->current_num_of_items > 0)
{
*item = &q->items[q->tail];
q->tail ++;
if (q->tail >= q->max_num_items) q->tail = 0;
q->current_num_of_items --;
}
else
{
error = TSQUEUE_FAILED_EMPTY;
}
// release the mutex lock
pthread_mutex_unlock(&q->mutex);
// signal empty
sem_post(&q->empty);
return error;
}
//=======================================================================
int tsqueue_number_of_items(tsqueue_st* q)
{
int num_items = 0;
if (q == NULL) return TSQUEUE_NOT_INITIALIZED;
// acquire the mutex lock
pthread_mutex_lock(&q->mutex);
num_items = q->current_num_of_items;
// release the mutex lock
pthread_mutex_unlock(&q->mutex);
return num_items;
}
//=======================================================================
int tsqueue_reset_dropped_counter(tsqueue_st* q)
{
if (q == NULL) return TSQUEUE_NOT_INITIALIZED;
pthread_mutex_lock(&q->mutex);
q->num_items_dropped = 0;
pthread_mutex_unlock(&q->mutex);
return TSQUEUE_OK;
}
//=======================================================================
int tsqueue_get_number_of_dropped(tsqueue_st* q)
{
int num_items = 0;
if (q == NULL) return TSQUEUE_NOT_INITIALIZED;
pthread_mutex_lock(&q->mutex);
num_items = q->num_items_dropped;
pthread_mutex_unlock(&q->mutex);
return num_items;
}

Wyświetl plik

@ -1,112 +0,0 @@
#ifndef __TSQUEUE_H__
#define __TSQUEUE_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdint.h>
#define TSQUEUE_TIMEOUT (1)
#define TSQUEUE_OK (0)
#define TSQUEUE_BUFFER_FULL (-1)
#define TSQUEUE_MEM_ALLOC_FAILED (-2)
#define TSQUEUE_SEM_INIT_FAILED (-3)
#define TSQUEUE_MUTEX_INIT_FAILED (-4)
#define TSQUEUE_NOT_INITIALIZED (-5)
#define TSQUEUE_FAILED_FULL (-6)
#define TSQUEUE_SEM_FAILED (-7)
#define TSQUEUE_FAILED_EMPTY (-8)
typedef struct
{
uint8_t *data;
int length;
uint32_t metadata; // can be a pointer context, a number, a set of flags, etc.
} tsqueue_item_st;
typedef struct
{
tsqueue_item_st *items;
int max_num_items;
int item_size_bytes;
int current_num_of_items;
int head;
int tail;
// The mutex lock, and the semaphores
pthread_mutex_t mutex;
sem_t full, empty;
int sema_inited;
int num_items_dropped;
} tsqueue_st;
/*
* Init the queue
* q: a pointer to a pre-allocated structure
* item_size_bytes: the maximal container size of each item in the queue (bytes)
* total_element_count: the total capacity of the cyclic queue
*/
int tsqueue_init(tsqueue_st* q, int item_size_bytes, int total_element_count);
/*
* Release the queue
*/
int tsqueue_release(tsqueue_st* q);
/*
* Push an item to the queue
* item: the contents of the item to be pushed. The item contents are cloned (copied)
* to the internal local copy, thus, this parameter may be changed as needed after the call
* Note: if the queue is full, the function returned immediatelly with an error. This dunctionality can
* be changed by letting the function block until space is freed up in the queue. When there is not
* sufficient space in the queue, the item is dropped and the "dropped" counter is increased.
*/
int tsqueue_insert_push_item(tsqueue_st* q, tsqueue_item_st* item, int timeout_us, int override);
/*
* Push a buffer to the queue
* The same as before, but rather than an "item", a specific buffer, length and metadata are
* cloned into the internal item local copy, and pushed to the queue
*/
int tsqueue_insert_push_buffer(tsqueue_st* q, uint8_t* buffer, int length, uint32_t metadata, int timeout_us, int override);
/*
* Pop an item from the queue with timeout
* item: the output of the function is a pointer to a single cell in the queue that has been
* popped. This item pointer is not cloned to the user but rather passed by reference.
* it is up to the user to create his own private copy of its contents as soon as he gets
* the pointer.
* Note: this function blocked until there is anything to pop. If the queue is empty, the queue will
* hold the calling thread in a blocking condition.
* For no timeout option pass 0 to timeout_ms
*/
int tsqueue_pop_item(tsqueue_st* q, tsqueue_item_st** item, int timeout_us);
/*
* Return the current number of items in the queue
*/
int tsqueue_number_of_items(tsqueue_st* q);
/*
* Clears the "dropped" counter value to zero.
*/
int tsqueue_reset_dropped_counter(tsqueue_st* q);
/*
* Return the current count value of the dropped items - those we wanted to push but couldn't due
* to insufficient capacity
*/
int tsqueue_get_number_of_dropped(tsqueue_st* q);
#ifdef __cplusplus
}
#endif
#endif // __TSQUEUE_H__

Wyświetl plik

@ -1,2 +0,0 @@
# build directories
build

Wyświetl plik

@ -1,25 +0,0 @@
cmake_minimum_required(VERSION 3.15)
project(cariboulite)
set(CMAKE_BUILD_TYPE Release)
# Bring the headers
set(SUPER_DIR ${PROJECT_SOURCE_DIR}/..)
include_directories(/.)
include_directories(${SUPER_DIR})
# Source files
set(SOURCES_LIB hat.c eeprom_utils.c)
set(SOURCES ${SOURCES_LIB} test_hat.c)
set(EXTERN_LIBS ${SUPER_DIR}/io_utils/build/libio_utils.a ${SUPER_DIR}/zf_log/build/libzf_log.a -lpthread)
add_compile_options(-Wall -Wextra -Wmissing-braces)
#Generate the static library from the sources
add_library(hat STATIC ${SOURCES_LIB})
target_link_libraries(hat rt m pthread)
#add_executable(test_hat ${SOURCES})
#target_link_libraries(test_hat rt pthread ${EXTERN_LIBS})
# Set the location for library installation -- i.e., /usr/lib in this case
# not really necessary in this example. Use "sudo make install" to apply
install(TARGETS hat DESTINATION /usr/lib)

Wyświetl plik

@ -1,4 +0,0 @@
[EEPROM Programming Tutorial](https://github.com/cariboulabs/cariboulite/tree/main/docs/flashing)
# License
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International License</a>.

Wyświetl plik

@ -1,181 +0,0 @@
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "EEPROM_UTILS"
#include "zf_log/zf_log.h"
#include "eeprom_utils.h"
#include "io_utils/io_utils_fs.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include <endian.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
//===========================================================
int eeprom_init_device(eeprom_utils_st *ee)
{
switch (ee->eeprom_type)
{
case eeprom_type_24c64: strcpy(ee->eeprom_type_name, "24c64"); ee->eeprom_size = 8192; break;
case eeprom_type_24c128: strcpy(ee->eeprom_type_name, "24c128"); ee->eeprom_size = 16384; break;
case eeprom_type_24c256: strcpy(ee->eeprom_type_name, "24c256"); ee->eeprom_size = 32768; break;
case eeprom_type_24c512: strcpy(ee->eeprom_type_name, "24c512"); ee->eeprom_size = 65536; break;
case eeprom_type_24c1024: strcpy(ee->eeprom_type_name, "24c1024"); ee->eeprom_size = 131072; break;
case eeprom_type_24c32:
default: strcpy(ee->eeprom_type_name, "24c32"); ee->eeprom_size = 4096; break; // lowest denominator
}
ee->bus = io_utils_i2cbus_exists();
if (ee->bus >= 0)
{
ZF_LOGI("i2c-%d has been found successfully", ee->bus);
}
// neither bus 0,9 were found in the dev dir -> we need to probe bus9
if (ee->bus == -1)
{
if (io_utils_probe_gpio_i2c() == -1)
{
ZF_LOGE("Failed to probe i2c-9");
return -1;
}
else
{
ee->bus = 9;
ZF_LOGI("i2c-9 has been probed successfully");
}
}
// probe the eeprom driver
ZF_LOGI("trying to modprobe at24");
char modprobe[] = "/usr/sbin/modprobe at24";
char *argv[64];
io_utils_parse_command(modprobe, argv);
if (io_utils_execute_command(argv) != 0)
{
ZF_LOGE("MODPROBE of the eeprom 'at24' execution failed");
return -1;
}
// the sys dir path
char sys_dir_bus[128] = {0};
char sys_dir_bus_addr[160] = {0};
char sys_dir_bus_new_dev[160] = {0};
sprintf(sys_dir_bus, "/sys/class/i2c-adapter/i2c-%d", ee->bus);
sprintf(sys_dir_bus_addr, "%s/%d-00%x", sys_dir_bus, ee->bus, ee->i2c_address);
sprintf(sys_dir_bus_new_dev, "%s/new_device", sys_dir_bus);
int dir = 0;
int ee_exists = io_utils_file_exists(sys_dir_bus_addr, NULL, &dir, NULL, NULL);
if (!ee_exists || !dir)
{
// create the device
char dev_type[64] = {0};
sprintf(dev_type, "%s 0x%x", ee->eeprom_type_name, ee->i2c_address);
if ( io_utils_write_to_file(sys_dir_bus_new_dev, dev_type, strlen(dev_type) + 1) != 0)
{
ZF_LOGE("EEPROM on addr 0x%x probing failed, retrying...", ee->i2c_address);
if (io_utils_write_to_file(sys_dir_bus_new_dev, dev_type, strlen(dev_type) + 1) != 0)
{
ZF_LOGE("EEPROM on addr 0x%x probing failed", ee->i2c_address);
return -1;
}
}
}
// recheck that the file exists now
ee_exists = io_utils_file_exists(sys_dir_bus_addr, NULL, &dir, NULL, NULL);
if (!ee_exists || !dir)
{
ZF_LOGE("EEPROM on addr 0x%x probing failed - file was not found", ee->i2c_address);
return -1;
}
ZF_LOGI("EEPROM on addr 0x%x probing successful", ee->i2c_address);
ee->initialized = true;
return 0;
}
//===========================================================
int eeprom_close_device(eeprom_utils_st *ee)
{
int dir = 0;
char sys_dir_bus[128] = {0};
char sys_dir_bus_addr[160] = {0};
char sys_dir_bus_del_dev[160] = {0};
if (ee->initialized == false)
{
ZF_LOGE("EEPROM device is not initialized");
return -1;
}
sprintf(sys_dir_bus, "/sys/class/i2c-adapter/i2c-%d", ee->bus);
sprintf(sys_dir_bus_addr, "%s/%d-00%x", sys_dir_bus, ee->bus, ee->i2c_address);
sprintf(sys_dir_bus_del_dev, "%s/delete_device", sys_dir_bus);
int ee_exists = io_utils_file_exists(sys_dir_bus_addr, NULL, &dir, NULL, NULL);
if (ee_exists && dir)
{
char dev_type[64] = {0};
sprintf(dev_type, "0x%x", ee->i2c_address);
if (io_utils_write_to_file(sys_dir_bus_del_dev, dev_type, strlen(dev_type) + 1) != 0)
{
ZF_LOGE("EEPROM on addr 0x%x deletion failed on bus %d", ee->i2c_address, ee->bus);
return -1;
}
}
ZF_LOGI("EEPROM addr 0x%x on bus %d deletion was successful", ee->i2c_address, ee->bus);
return 0;
}
//===========================================================
int eeprom_write(eeprom_utils_st *ee, char* buffer, int length)
{
char eeprom_fname[200] = {0};
sprintf(eeprom_fname, "/sys/class/i2c-adapter/i2c-%d/%d-00%x/eeprom",
ee->bus, ee->bus, ee->i2c_address);
int ee_exists = io_utils_file_exists(eeprom_fname, NULL, NULL, NULL, NULL);
if (!ee_exists)
{
ZF_LOGE("The eeprom driver for bus %d, adde 0x%x is not initialized", ee->bus, ee->i2c_address);
return -1;
}
if (length > ee->eeprom_size)
{
ZF_LOGW("EEPROM write size (length=%d) exceeds %d bytes, truncating", length, ee->eeprom_size);
length = ee->eeprom_size;
}
return io_utils_write_to_file(eeprom_fname, buffer, length);
}
//===========================================================
int eeprom_read(eeprom_utils_st *ee, char* buffer, int length)
{
char eeprom_fname[200] = {0};
sprintf(eeprom_fname, "/sys/class/i2c-adapter/i2c-%d/%d-00%x/eeprom",
ee->bus, ee->bus, ee->i2c_address);
int ee_exists = io_utils_file_exists(eeprom_fname, NULL, NULL, NULL, NULL);
if (!ee_exists)
{
ZF_LOGE("The eeprom driver for bus %d, adde 0x%x is not initialized", ee->bus, ee->i2c_address);
return -1;
}
if (length > ee->eeprom_size)
{
ZF_LOGW("EEPROM read size (length=%d) exceeds %d bytes, truncating", length, ee->eeprom_size);
length = ee->eeprom_size;
}
return io_utils_read_from_file(eeprom_fname, buffer, length);
}

Wyświetl plik

@ -1,42 +0,0 @@
#ifndef __EEPROM_UTILS_H__
#define __EEPROM_UTILS_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
/* EEPROM types */
typedef enum
{
eeprom_type_24c32 = 4096,
eeprom_type_24c64 = 8192,
eeprom_type_24c128 = 16384,
eeprom_type_24c256 = 32768,
eeprom_type_24c512 = 65536,
eeprom_type_24c1024 = 131072,
} eeprom_type_en;
typedef struct
{
uint8_t i2c_address;
eeprom_type_en eeprom_type;
char eeprom_type_name[32];
int bus;
int eeprom_size;
int initialized;
} eeprom_utils_st;
int eeprom_init_device(eeprom_utils_st *ee);
int eeprom_close_device(eeprom_utils_st *ee);
int eeprom_write(eeprom_utils_st *ee, char* buffer, int length);
int eeprom_read(eeprom_utils_st *ee, char* buffer, int length);
#ifdef __cplusplus
}
#endif
#endif // __EEPROM_UTILS_H__

Wyświetl plik

@ -1,721 +0,0 @@
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "HAT"
#include "zf_log/zf_log.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include <endian.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "io_utils/io_utils_fs.h"
#include "hat.h"
//===========================================================
int serial_from_uuid(char* uuid, uint32_t *serial)
{
uint32_t data0 = 0, data4 = 0;
uint16_t data1 = 0, data2 = 0, data3 = 0, data5 = 0;
uint32_t ser1, ser2, ser3, ser4;
if (sscanf(uuid, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
&data0, &data1, &data2,
&data3, &data4, &data5) != 6)
{
ZF_LOGE("the uuid '%s' is not valid", uuid);
return -1;
}
ser1 = data5;
ser2 = (data4 & 0xFFFF) | (data3 << 16);
ser3 = (data2 & 0xFFFF) | (data1 << 16);
ser4 = data0;
if (serial) *serial = ser1 ^ ser2 ^ ser3 ^ ser4;
return 0;
}
//===========================================================
static uint16_t getcrc(char* data, unsigned int size)
{
uint16_t out = 0;
int bits_read = 0, bit_flag;
/* Sanity check: */
if((data == NULL) || size == 0)
return 0;
while(size > 0)
{
bit_flag = out >> 15;
/* Get next bit: */
out <<= 1;
// item a) work from the least significant bits
out |= (*data >> bits_read) & 1;
/* Increment bit counter: */
bits_read++;
if(bits_read > 7)
{
bits_read = 0;
data++;
size--;
}
/* Cycle check: */
if(bit_flag)
out ^= CRC16_POLY;
}
// item b) "push out" the last 16 bits
int i;
for (i = 0; i < 16; ++i) {
bit_flag = out >> 15;
out <<= 1;
if(bit_flag)
out ^= CRC16_POLY;
}
// item c) reverse the bits
uint16_t crc = 0;
i = 0x8000;
int j = 0x0001;
for (; i != 0; i >>=1, j <<= 1) {
if (i & out) crc |= j;
}
return crc;
}
//===========================================================
static void hat_print_header(struct header_t *header)
{
ZF_LOGD("# Header: signature=0x%08x", header->signature);
ZF_LOGD("# Header: format version=0x%02x", header->ver);
ZF_LOGD("# Header: reserved=%u", header->res);
ZF_LOGD("# Header: numatoms=%u", header->numatoms);
ZF_LOGD("# Header: eeplen=%u", header->eeplen);
}
//===========================================================
static void hat_print_vendor(struct vendor_info_t * vinf)
{
ZF_LOGD("Vendor info: product_uuid %08x-%04x-%04x-%04x-%04x%08x",
vinf->serial_4,
vinf->serial_3>>16,
vinf->serial_3 & 0xffff,
vinf->serial_2>>16,
vinf->serial_2 & 0xffff,
vinf->serial_1);
ZF_LOGD("Vendor info: raw serial numbers %08x %08x %08x %08x",
vinf->serial_4,
vinf->serial_3,
vinf->serial_2,
vinf->serial_1);
ZF_LOGD("Vendor info: product_id 0x%04x", vinf->pid);
ZF_LOGD("Vendor info: product_ver 0x%04x", vinf->pver);
ZF_LOGD("Vendor info: vendor \"%s\" # length=%u", vinf->vstr, vinf->vslen);
ZF_LOGD("Vendor info: product \"%s\" # length=%u", vinf->pstr, vinf->pslen);
}
//===========================================================
static void hat_print_gpio(struct gpio_map_t *gpiomap)
{
ZF_LOGD("GPIO map info: gpio_drive %d", gpiomap->flags & 15); //1111
ZF_LOGD("GPIO map info: gpio_slew %d", (gpiomap->flags & 48)>>4); //110000
ZF_LOGD("GPIO map info: gpio_hysteresis %d", (gpiomap->flags & 192)>>6); //11000000
ZF_LOGD("GPIO map info: back_power %d", gpiomap->power);
for (int j = 0; j<28; j++)
{
if (gpiomap->pins[j] & (1<<7))
{
//board uses this pin
char *pull_str = "INVALID";
switch ((gpiomap->pins[j] & 96)>>5) { //1100000
case 0: pull_str = "PULL DEFAULT";
break;
case 1: pull_str = "PULL UP";
break;
case 2: pull_str = "PULL DOWN";
break;
case 3: pull_str = "PULL NONE";
break;
}
char *func_str = "INVALID";
switch ((gpiomap->pins[j] & 7)) { //111
case 0: func_str = "INPUT";
break;
case 1: func_str = "OUTPUT";
break;
case 4: func_str = "ALT0";
break;
case 5: func_str = "ALT1";
break;
case 6: func_str = "ALT2";
break;
case 7: func_str = "ALT3";
break;
case 3: func_str = "ALT4";
break;
case 2: func_str = "ALT5";
break;
}
ZF_LOGD("# GPIO map info: setgpio %d %s %s", j, func_str, pull_str);
}
}
}
//===========================================================
static void hat_print_dt_data(struct dt_data_t *data)
{
ZF_LOGD("# Device Tree info: length = %d", data->dt_data_size);
}
//===========================================================
static int hat_valid(hat_st *hat)
{
if (!hat->initialized)
{
ZF_LOGE("eeprom driver is not initialized");
return -1;
}
uint8_t *location = (uint8_t*)hat->read_buffer;
uint32_t offset = 0;
// check the header
struct header_t* header = (struct header_t*)location;
if (header->signature != HEADER_SIGN || header->ver != FORMAT_VERSION)
{
// signature: 0x52, 0x2D, 0x50, 0x69 ("R-Pi" in ASCII)
// EEPROM data format version (0x00 reserved, 0x01 = first version)
ZF_LOGD("Signature (0x%08X) / version (0x%02X) not valid", header->signature, header->ver);
return 0; // not valid
}
if (header->res != 0)
{
ZF_LOGD("Reserved field not zero (0x%08X)", header->res);
return 0; // not valid
}
if (header->numatoms < 2)
{
ZF_LOGD("Number of atoms smaller than 3 (%d)", header->numatoms);
return 0; // not valid
}
if (header->eeplen > (uint32_t)(hat->read_buffer_size))
{
ZF_LOGD("The declared data-size larger than eeprom size (%d > %d)",
header->eeplen, hat->read_buffer_size);
return 0; // not valid
}
// Now check every atom and check its validity
// we won't dive deeper in the atoms as the crc16 should be sufficiently
// informative on the validity in addition to all the constants etc.
int i;
location += sizeof(struct header_t);
offset += sizeof(struct header_t);
for (i = 0; i<header->numatoms; i++)
{
struct atom_t *atom = (struct atom_t *)location;
if (atom->type != ATOM_VENDOR_TYPE &&
atom->type != ATOM_GPIO_TYPE &&
atom->type != ATOM_DT_TYPE &&
atom->type != ATOM_CUSTOM_TYPE)
{
ZF_LOGD("Found an invalid atom type (%d @ #%d)", atom->type, i);
return 0; // not valid
}
if (atom->count != i)
{
ZF_LOGD("Atom #%d count inconcistent (%d)", i, atom->count);
return 0; // not valid
}
if ((offset + ATOM_TOTAL_SIZE(atom)) > (uint32_t)(hat->read_buffer_size))
{
ZF_LOGD("Atom #%d data length + crc16 don't fit into eeprom", i);
return 0; // not valid
}
// calculate crc
uint16_t calc_crc = getcrc((char*)atom, ATOM_DATA_SIZE(atom));
uint16_t actual_crc = ATOM_CRC(atom);
if (actual_crc != calc_crc)
{
ZF_LOGD("Atom #%d calc_crc (0x%04X) doesn't match the actual_crc (0x%04X)",
i, calc_crc, actual_crc);
return 0; // not valid
}
location += ATOM_TOTAL_SIZE(atom);
offset += ATOM_TOTAL_SIZE(atom);
}
if (header->eeplen != offset)
{
ZF_LOGD("The eeprom header total length doesn't match contents calculated size (%d <=> %d)",
header->eeplen, offset);
return 0; // not valid
}
return 1; // valid
}
//===========================================================
static int hat_contents_parse(hat_st *hat)
{
uint8_t *location = NULL;
if (!hat->initialized)
{
ZF_LOGE("eeprom driver is not initialized");
return 0;
}
ZF_LOGD("Reading eeprom configuration (%d bytes)...", hat->read_buffer_size);
if (eeprom_read(&hat->dev, hat->read_buffer, hat->read_buffer_size) < 0)
{
ZF_LOGE("Reading from eeprom failed");
return -1;
}
// check the eeprom data's validity
if ( !hat_valid(hat) )
{
ZF_LOGE("EEPROM data is not valid. Try reconfiguring it.");
return -1;
}
location = (uint8_t*)hat->read_buffer;
// Header
memcpy(&hat->header, location, sizeof(hat->header));
location += sizeof(hat->header);
// Atoms
for (int i = 0; i < hat->header.numatoms; i++)
{
struct atom_t *atom = (struct atom_t *)location;
uint8_t *atom_data = location + ATOM_HEADER_SIZE;
// Analyze he atom internal infomration
switch (atom->type)
{
//-------------------------------------------------------------
case ATOM_VENDOR_TYPE:
{
uint8_t *it = atom_data;
memcpy(&hat->vinf, it, VENDOR_STATIC_SIZE); it += VENDOR_STATIC_SIZE;
memcpy(&hat->vinf.vstr, it, hat->vinf.vslen); it += hat->vinf.vslen;
memcpy(&hat->vinf.pstr, it, hat->vinf.pslen); it += hat->vinf.pslen;
hat->vinf.vstr[hat->vinf.vslen] = 0;
hat->vinf.pstr[hat->vinf.pslen] = 0;
} break;
//-------------------------------------------------------------
case ATOM_GPIO_TYPE:
{
memcpy(&hat->gpiomap, atom_data, GPIO_MAP_SIZE);
} break;
//-------------------------------------------------------------
case ATOM_DT_TYPE:
{
ZF_LOGD("Atom datalength = %d", atom->dlen - 2); // substruct the crc16 size from the dlen
hat->dt_data.dt_data = (char*)malloc(atom->dlen - 2);
if (hat->dt_data.dt_data == NULL)
{
ZF_LOGE("Failed allocating dt data.");
return -1;
}
hat->dt_data.dt_data_size = atom->dlen - 2;
memcpy(hat->dt_data.dt_data, atom_data, hat->dt_data.dt_data_size);
} break;
//-------------------------------------------------------------
default:
ZF_LOGE("Error: unrecognised atom type");
break;
}
location += ATOM_TOTAL_SIZE(atom);
}
return 0;
}
//===========================================================
int hat_fill_in(hat_st *hat)
{
struct atom_t *atom = NULL;
uint8_t *location = (uint8_t *)hat->write_buffer;
struct header_t* header = (struct header_t*)hat->write_buffer;
// Header generation
// -------------------------------------------------------
header->signature = HEADER_SIGN;
header->ver = FORMAT_VERSION;
header->res = 0;
header->numatoms = 0;
header->eeplen = sizeof(struct header_t);
// Vendor information generation
// -------------------------------------------------------
location += header->eeplen;
atom = (struct atom_t*)location;
struct vendor_info_t* vinf = (struct vendor_info_t*)(location + ATOM_HEADER_SIZE);
vinf->pid = hat->product_id;
vinf->pver = hat->product_version;
vinf->vslen = strlen(hat->vendor_name);
vinf->pslen = strlen(hat->product_name);
strcpy(VENDOR_VSTR_POINT(vinf), hat->vendor_name);
strcpy(VENDOR_PSTR_POINT(vinf), hat->product_name);
// read 128 random bits from /dev/urandom
int random_file = open("/dev/urandom", O_RDONLY);
void* temp_serial_loc = (void*)&vinf->serial_1;
ssize_t result = read(random_file, temp_serial_loc, 16);
close(random_file);
if (result <= 0)
{
printf("Unable to read from /dev/urandom to set up UUID");
return -1;
}
else
{
//put in the version
vinf->serial_3 = (vinf->serial_3 & 0xffff0fff) | 0x00004000;
//put in the variant
vinf->serial_2 = (vinf->serial_2 & 0x3fffffff) | 0x80000000;
printf("Gen UUID=%08x-%04x-%04x-%04x-%04x%08x\n", vinf->serial_4,
vinf->serial_3>>16,
vinf->serial_3 & 0xffff,
vinf->serial_2>>16,
vinf->serial_2 & 0xffff,
vinf->serial_1);
sprintf(hat->generated_uuid, "%08x-%04x-%04x-%04x-%04x%08x", vinf->serial_4,
vinf->serial_3>>16,
vinf->serial_3 & 0xffff,
vinf->serial_2>>16,
vinf->serial_2 & 0xffff,
vinf->serial_1);
serial_from_uuid(hat->generated_uuid, &hat->generated_serial);
}
atom->type = ATOM_VENDOR_TYPE;
atom->count = header->numatoms;
atom->dlen = VENDOR_INFO_COMPACT_SIZE(vinf) + 2;
ATOM_CRC(atom) = getcrc((char*)atom, ATOM_DATA_SIZE(atom));
header->eeplen += ATOM_TOTAL_SIZE(atom);
header->numatoms += 1;
// GPIO map information
// -------------------------------------------------------
location += ATOM_TOTAL_SIZE(atom);
atom = (struct atom_t*)location;
atom->type = ATOM_GPIO_TYPE;
atom->count = header->numatoms;
atom->dlen = GPIO_MAP_SIZE + 2;
struct gpio_map_t* gpio = (struct gpio_map_t*)(location+ATOM_HEADER_SIZE);
gpio->flags = 0; // drive, slew, hysteresis => 0=leave at default
gpio->power = 0; // 0 = no back power
// MAPPING: (func,pull,used)
// [2:0] func_sel GPIO function as per FSEL GPIO register field in BCM2835 datasheet
// [4:3] reserved set to 0
// [6:5] pulltype 0=leave at default setting, 1=pullup, 2=pulldown, 3=no pull
// [ 7] is_used 1=board uses this pin, 0=not connected and therefore not used
gpio->pins[2] = GPIO_MAP_BITS(5,2,0); // SMI SA3
gpio->pins[3] = GPIO_MAP_BITS(5,2,0); // SMI SA2
gpio->pins[4] = GPIO_MAP_BITS(1,0,1); // FPGA SOFT RESET
gpio->pins[5] = GPIO_MAP_BITS(1,0,1); // MXR_RESET
gpio->pins[6] = GPIO_MAP_BITS(5,2,1); // SMI SOE_SE
gpio->pins[7] = GPIO_MAP_BITS(5,2,1); // SMI SWE_SRW
gpio->pins[8] = GPIO_MAP_BITS(5,0,1); // SMI SD0
gpio->pins[9] = GPIO_MAP_BITS(5,0,1); // SMI SD1
gpio->pins[10] = GPIO_MAP_BITS(5,0,1); // SMI SD2
gpio->pins[11] = GPIO_MAP_BITS(5,0,1); // SMI SD3
gpio->pins[12] = GPIO_MAP_BITS(5,0,1); // SMI SD4
gpio->pins[13] = GPIO_MAP_BITS(5,0,1); // SMI SD5
gpio->pins[14] = GPIO_MAP_BITS(5,0,1); // SMI SD6
gpio->pins[15] = GPIO_MAP_BITS(5,0,1); // SMI SD7
gpio->pins[16] = GPIO_MAP_BITS(0,0,1); // SPI1 CS #2 - MIXER
gpio->pins[17] = GPIO_MAP_BITS(0,0,1); // SPI1 CS #1 - MODEM
gpio->pins[18] = GPIO_MAP_BITS(0,0,1); // SPI1 CS #0 - FPGA
gpio->pins[19] = GPIO_MAP_BITS(0,0,1); // SPI1 MISO
gpio->pins[20] = GPIO_MAP_BITS(0,0,1); // SPI1 MOSI
gpio->pins[21] = GPIO_MAP_BITS(0,0,1); // SPI1 SCK
gpio->pins[22] = GPIO_MAP_BITS(0,1,1); // MODEM IRQ
gpio->pins[23] = GPIO_MAP_BITS(1,0,1); // MODEM RESET
gpio->pins[24] = GPIO_MAP_BITS(5,0,1); // SMI READ_REQ
gpio->pins[25] = GPIO_MAP_BITS(5,0,1); // SMI WRITE_REQ
gpio->pins[26] = GPIO_MAP_BITS(1,0,1); // FPGA RESET
gpio->pins[27] = GPIO_MAP_BITS(0,0,1); // FPGA CDONE
ATOM_CRC(atom) = getcrc((char*)atom, ATOM_DATA_SIZE(atom));
header->eeplen += ATOM_TOTAL_SIZE(atom);
header->numatoms += 1;
// Device Tree information
// -------------------------------------------------------
location += ATOM_TOTAL_SIZE(atom);
atom = (struct atom_t*)location;
atom->type = ATOM_DT_TYPE;
atom->count = header->numatoms;
atom->dlen = hat->device_tree_buffer_size + 2;
uint8_t *dt_data = (uint8_t *)(location+ATOM_HEADER_SIZE);
memcpy(dt_data, hat->device_tree_buffer, hat->device_tree_buffer_size);
ATOM_CRC(atom) = getcrc((char*)atom, ATOM_DATA_SIZE(atom));
header->eeplen += ATOM_TOTAL_SIZE(atom);
header->numatoms += 1;
hat->write_buffer_used_size = header->eeplen;
return 0;
}
//===========================================================
int hat_init(hat_st *hat)
{
ZF_LOGD("Initializing eeprom driver");
if (eeprom_init_device(&hat->dev) != 0)
{
ZF_LOGE("Initializing hat driver failed");
return -1;
}
hat->read_buffer = NULL;
hat->write_buffer = NULL;
hat->read_buffer_size = hat->dev.eeprom_size;
hat->read_buffer = (char *)malloc(hat->read_buffer_size);
if (hat->read_buffer == NULL)
{
ZF_LOGE("hat read buffer allocation failed");
eeprom_close_device(&hat->dev);
return -1;
}
hat->write_buffer_size = hat->dev.eeprom_size;
hat->write_buffer = (char *)malloc(hat->write_buffer_size);
if (hat->write_buffer == NULL)
{
ZF_LOGE("hat write buffer allocation failed");
eeprom_close_device(&hat->dev);
return -1;
}
hat->write_buffer_used_size = 0;
hat->initialized = true;
// check if the eeprom is initialized (of contains FFFF garbage)
hat->eeprom_initialized = false;
if (eeprom_read(&hat->dev, hat->read_buffer, hat->read_buffer_size) < 0)
{
ZF_LOGE("Reading from eeprom failed");
return -1;
}
hat->eeprom_initialized = hat_valid(hat);
hat_contents_parse(hat);
return 0;
}
//===========================================================
int hat_close(hat_st *hat)
{
ZF_LOGD("closing hat driver");
if (!hat->initialized)
{
ZF_LOGE("hat is not initialized");
return -1;
}
if (hat->read_buffer != NULL) free(hat->read_buffer);
if (hat->write_buffer != NULL) free(hat->write_buffer);
hat->read_buffer_size = 0;
hat->write_buffer_size = 0;
return 0;
}
//===========================================================
int hat_generate_write_config(hat_st *hat, bool overwrite)
{
if (!hat->eeprom_initialized || overwrite)
{
ZF_LOGD("Filling in HAT information");
hat_fill_in(hat);
ZF_LOGD("Writing into HAT");
eeprom_write(&hat->dev, hat->write_buffer, hat->write_buffer_used_size);
ZF_LOGD("Writing into HAT - Done");
}
else
{
sprintf(hat->generated_uuid, "%08x-%04x-%04x-%04x-%04x%08x", hat->vinf.serial_4,
hat->vinf.serial_3>>16,
hat->vinf.serial_3 & 0xffff,
hat->vinf.serial_2>>16,
hat->vinf.serial_2 & 0xffff,
hat->vinf.serial_1);
serial_from_uuid(hat->generated_uuid, &hat->generated_serial);
}
return 0;
}
//===========================================================
int hat_print(hat_st *hat)
{
if (!hat->eeprom_initialized)
{
if (hat_contents_parse(hat) != 0)
{
ZF_LOGE("Parsing EEPROM data failed - try reconfiguring");
return -1;
}
}
hat_print_header(&hat->header);
hat_print_vendor(&hat->vinf);
hat_print_gpio(&hat->gpiomap);
hat_print_dt_data(&hat->dt_data);
return 0;
}
//===========================================================
// If the board is not detected, try detecting it outside:
// go directly to the eeprom configuration application
// prompt the user
// configure and tell the user he needs to reboot his system
int hat_detect_board(hat_board_info_st *info)
{
int exists = 0;
int size, dir, file, dev;
// check if a hat is attached anyway..
char hat_dir_path[] = "/proc/device-tree/hat";
exists = io_utils_file_exists(hat_dir_path, &size, &dir, &file, &dev);
if (!exists || !dir)
{
ZF_LOGI("This board is not configured yet as a hat.");
return 0;
}
io_utils_read_string_from_file(hat_dir_path, "name", info->category_name, sizeof(info->category_name));
io_utils_read_string_from_file(hat_dir_path, "product", info->product_name, sizeof(info->product_name));
io_utils_read_string_from_file(hat_dir_path, "product_id", info->product_id, sizeof(info->product_id));
io_utils_read_string_from_file(hat_dir_path, "product_ver", info->product_version, sizeof(info->product_version));
io_utils_read_string_from_file(hat_dir_path, "uuid", info->product_uuid, sizeof(info->product_uuid));
io_utils_read_string_from_file(hat_dir_path, "vendor", info->product_vendor, sizeof(info->product_vendor));
// numeric version
if (info->product_version[0] == '0' && (info->product_version[1] == 'x' ||
info->product_version[1] == 'X'))
sscanf(info->product_version, "0x%08x", &info->numeric_version);
else
sscanf(info->product_version, "%08x", &info->numeric_version);
// numeric productid
if (info->product_id[0] == '0' && (info->product_id[1] == 'x' || info->product_id[1] == 'X'))
sscanf(info->product_id, "0x%08x", &info->numeric_product_id);
else
sscanf(info->product_id, "%08x", &info->numeric_product_id);
// serial number
if (serial_from_uuid(info->product_uuid, &info->numeric_serial_number) != 0)
{
// should never happen
return 0;
}
return 1;
}
//===========================================================
int hat_detect_from_eeprom(hat_board_info_st *info)
{
hat_st hat =
{
.dev =
{
.i2c_address = 0x50, // the i2c address of the eeprom chip
.eeprom_type = eeprom_type_24c32,
},
};
if (hat_init(&hat) != 0 || (info == NULL))
{
return -1;
}
if (!hat.eeprom_initialized)
{
hat_close(&hat);
return 0;
}
sprintf(info->category_name, "hat");
memcpy(info->product_name, VENDOR_PSTR_POINT(&hat.vinf), hat.vinf.pslen);
info->product_name[hat.vinf.pslen] = 0;
sprintf(info->product_id, "%d", hat.vinf.pid);
sprintf(info->product_version, "%d", hat.vinf.pver);
memcpy(info->product_vendor, VENDOR_VSTR_POINT(&hat.vinf), hat.vinf.vslen);
info->product_vendor[hat.vinf.vslen] = 0;
sprintf(info->product_uuid, "%08x-%04x-%04x-%04x-%04x%08x", hat.vinf.serial_4,
hat.vinf.serial_3>>16,
hat.vinf.serial_3 & 0xffff,
hat.vinf.serial_2>>16,
hat.vinf.serial_2 & 0xffff,
hat.vinf.serial_1);
info->numeric_version = hat.vinf.pver;
info->numeric_product_id = hat.vinf.pid;
serial_from_uuid(info->product_uuid, &info->numeric_serial_number);
hat_close(&hat);
return 1;
}
//===========================================================
void hat_print_board_info(hat_board_info_st *info, bool log)
{
if (log)
{
ZF_LOGD("# Board Info - Category name: %s", info->category_name);
ZF_LOGD("# Board Info - Product name: %s", info->product_name);
ZF_LOGD("# Board Info - Product ID: %s, Numeric: %d", info->product_id, info->numeric_product_id);
ZF_LOGD("# Board Info - Product Version: %s, Numeric: %d", info->product_version, info->numeric_version);
ZF_LOGD("# Board Info - Product UUID: %s, Numeric serial: 0x%08X", info->product_uuid, info->numeric_serial_number);
ZF_LOGD("# Board Info - Vendor: %s", info->product_vendor);
}
else
{
printf(" Category name: %s\n", info->category_name);
printf(" Product name: %s\n", info->product_name);
printf(" Product ID: %s, Numeric: %d\n", info->product_id, info->numeric_product_id);
printf(" Product Version: %s, Numeric: %d\n", info->product_version, info->numeric_version);
printf(" Product UUID: %s, Numeric serial: 0x%08X\n", info->product_uuid, info->numeric_serial_number);
printf(" Vendor: %s\n", info->product_vendor);
}
}

Wyświetl plik

@ -1,173 +0,0 @@
#ifndef __HAT_H__
#define __HAT_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "eeprom_utils.h"
/* Header type */
#define FORMAT_VERSION 0x01
#define MAX_STRLEN 256
// Signature is "R-Pi" in ASCII. It is required to reversed (little endian) on disk.
#define HEADER_SIGN be32toh((((char)'R' << 24) | ((char)'-' << 16) | ((char)'P' << 8) | ((char)'i')))
/* Atom type */
#define ATOM_INVALID_TYPE 0x0000
#define ATOM_VENDOR_TYPE 0x0001
#define ATOM_GPIO_TYPE 0x0002
#define ATOM_DT_TYPE 0x0003
#define ATOM_CUSTOM_TYPE 0x0004
#define ATOM_HINVALID_TYPE 0xffff
#define ATOM_VENDOR_NUM 0x0000
#define ATOM_GPIO_NUM 0x0001
#define ATOM_DT_NUM 0x0002
#define CRC16_POLY 0x8005
/* GPIO type */
#define GPIO_MIN 2
#define GPIO_COUNT 28
/* EEPROM header structure */
struct header_t {
uint32_t signature;
unsigned char ver;
unsigned char res;
uint16_t numatoms;
uint32_t eeplen;
};
#define HEADER_SIZE ( sizeof(struct header_t) )
/* Atom structure */
struct atom_t
{
uint16_t type;
uint16_t count;
uint32_t dlen;
char* data;
uint16_t crc16;
};
#define ATOM_HEADER_SIZE ( 8 )
#define ATOM_CRC_SIZE ( 2 )
#define ATOM_DATA_SIZE(a) ( ATOM_HEADER_SIZE + ((a)->dlen) - 2 ) // at the dlen includes the CRC16 size
#define ATOM_CRC(a) ( *(uint16_t*)( ((uint8_t*)(a)) + ATOM_DATA_SIZE(a) ) )
#define ATOM_TOTAL_SIZE(a) ( ATOM_DATA_SIZE(a) + ATOM_CRC_SIZE)
/* Vendor info atom data */
struct vendor_info_t
{
uint32_t serial_1; //least significant
uint32_t serial_2;
uint32_t serial_3;
uint32_t serial_4; //most significant
uint16_t pid;
uint16_t pver;
unsigned char vslen;
unsigned char pslen;
char vstr[MAX_STRLEN + 1];
char pstr[MAX_STRLEN + 1];
};
#define VENDOR_STATIC_SIZE ( 4*sizeof(uint32_t) + 2*sizeof(uint16_t) + 2*sizeof(char) )
#define VENDOR_VSTR_POINT(v) ( (char*)(v) + VENDOR_STATIC_SIZE )
#define VENDOR_PSTR_POINT(v) ( (char*)(v) + VENDOR_STATIC_SIZE + (v)->vslen )
#define VENDOR_INFO_COMPACT_SIZE(v) ( VENDOR_STATIC_SIZE + (v)->vslen + (v)->pslen )
/* GPIO map atom data */
struct gpio_map_t
{
unsigned char flags;
unsigned char power;
unsigned char pins[GPIO_COUNT];
};
#define GPIO_MAP_SIZE (sizeof(struct gpio_map_t))
// [2:0] func_sel GPIO function as per FSEL GPIO register field in BCM2835 datasheet
// [4:3] reserved set to 0
// [6:5] pulltype 0=leave at default setting, 1=pullup, 2=pulldown, 3=no pull
// [ 7] is_used 1=board uses this pin, 0=not connected and therefore not used
#define GPIO_MAP_BITS(func,pull,used) ( (uint8_t)( ((func)&0x7) | ((pull)&0x3)<<5 | ((used)&0x1)<<7 ) )
struct dt_data_t
{
char* dt_data;
uint32_t dt_data_size;
};
#define INFO_MAX_LEN 64
typedef struct
{
char category_name[INFO_MAX_LEN];
char product_name[INFO_MAX_LEN];
char product_id[INFO_MAX_LEN];
char product_version[INFO_MAX_LEN];
char product_uuid[INFO_MAX_LEN];
char product_vendor[INFO_MAX_LEN];
uint32_t numeric_serial_number;
uint32_t numeric_version;
uint32_t numeric_product_id;
} hat_board_info_st;
typedef struct
{
char vendor_name[MAX_STRLEN];
char product_name[MAX_STRLEN];
int product_id;
int product_version;
unsigned char* device_tree_buffer;
int device_tree_buffer_size;
// eeprom device
eeprom_utils_st dev;
// buffers (read and write)
char* read_buffer;
int read_buffer_size;
char* write_buffer;
int write_buffer_size;
int write_buffer_used_size;
// hat initialized
bool initialized;
// eeprom contains valid information (not FFF)
bool eeprom_initialized;
// hat definitions
struct header_t header;
struct vendor_info_t vinf;
struct gpio_map_t gpiomap;
struct dt_data_t dt_data;
unsigned char* custom_data;
// temporary date
char generated_uuid[128];
uint32_t generated_serial;
} hat_st;
int hat_init(hat_st *ee);
int hat_close(hat_st *ee);
int hat_fill_in(hat_st *ee);
int hat_print(hat_st *ee);
int hat_generate_write_config(hat_st *ee, bool overwrite);
// HAT functions after configuration is written and system is
// restarted. In this stage the sysfs shall contain the hat definitions
int hat_detect_board(hat_board_info_st *info);
int hat_detect_from_eeprom(hat_board_info_st *info);
void hat_print_board_info(hat_board_info_st *info, bool log);
int serial_from_uuid(char* uuid, uint32_t *serial);
#ifdef __cplusplus
}
#endif
#endif // __HAT_H__

Wyświetl plik

@ -1,38 +0,0 @@
#include <stdio.h>
#include "../cariboulite_dtbo.h"
#include "hat.h"
hat_st hat =
{
.vendor_name = "CaribouLabs LTD",
.product_name = "CaribouLite RPI Hat",
.product_id = 0x01,
.product_version = 0x01,
.device_tree_buffer = cariboulite_dtbo,
.device_tree_buffer_size = sizeof(cariboulite_dtbo),
.dev = {
.i2c_address = 0x50, // the i2c address of the eeprom chip
.eeprom_type = eeprom_type_24c32,
},
};
int main()
{
if (hat_init(&hat) != 0)
{
printf("error\n");
return 0;
}
hat_print(&hat);
hat_board_info_st info = {0};
hat_detect_board(&info);
hat_print_board_info(&info);
hat_close(&hat);
return 0;
}

Wyświetl plik

@ -1,104 +0,0 @@
cmake_minimum_required(VERSION 3.1.0)
project(iir VERSION 1.9.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "RelWithDebInfo")
endif()
cmake_policy(SET CMP0048 NEW) # set VERSION in project()
cmake_policy(SET CMP0042 NEW) # enable MACOSX_RPATH by default
include(GNUInstallDirs)
add_subdirectory(test)
add_subdirectory(demo)
enable_testing ()
if (MSVC)
add_compile_options(/W4)
else()
add_compile_options(-Wall -Wconversion -Wextra -pedantic)
endif()
set(LIBSRC
iir/Biquad.cpp
iir/Butterworth.cpp
iir/Cascade.cpp
iir/ChebyshevI.cpp
iir/ChebyshevII.cpp
iir/Custom.cpp
iir/PoleFilter.cpp
iir/RBJ.cpp)
set(LIBINCLUDE
iir/Biquad.h
iir/Butterworth.h
iir/Cascade.h
iir/ChebyshevI.h
iir/ChebyshevII.h
iir/Common.h
iir/Custom.h
iir/Layout.h
iir/MathSupplement.h
iir/PoleFilter.h
iir/RBJ.h
iir/State.h
iir/Types.h)
add_library(iir SHARED ${LIBSRC})
add_library(iir::iir ALIAS iir)
target_include_directories(iir
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> # for Iir.h
PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/iir> # everything else
)
set_target_properties(iir PROPERTIES
SOVERSION 1
VERSION ${PROJECT_VERSION}
PUBLIC_HEADER Iir.h
PRIVATE_HEADER "${LIBINCLUDE}")
install(TARGETS iir EXPORT iir-targets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/iir)
configure_file(iir.pc.in iir.pc @ONLY)
add_library(iir_static STATIC ${LIBSRC})
add_library(iir::iir_static ALIAS iir_static)
target_include_directories(iir_static
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> # for Iir.h
PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/iir> # everything else
)
set_target_properties(iir_static PROPERTIES
POSITION_INDEPENDENT_CODE TRUE
VERSION ${PROJECT_VERSION}
PUBLIC_HEADER Iir.h
PRIVATE_HEADER "${LIBINCLUDE}")
install(TARGETS iir_static EXPORT iir-targets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
PRIVATE_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/iir)
install(EXPORT iir-targets
DESTINATION lib/cmake/iir
NAMESPACE iir::
FILE iir-config.cmake
)

Wyświetl plik

@ -1,22 +0,0 @@
MIT License
Copyright (c) 2009 Vinnie Falco
Copyright (c) 2012 Bernd Porr
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Wyświetl plik

@ -1,55 +0,0 @@
/**
*
* "A Collection of Useful C++ Classes for Digital Signal Processing"
* By Vinnie Falco and Bernd Porr
*
* Official project location:
* https://github.com/berndporr/iir1
*
* --------------------------------------------------------------------------
*
* License: MIT License (http://www.opensource.org/licenses/mit-license.php)
* Copyright (c) 2009 by Vinnie Falco
* Copyright (c) 2011 by Bernd Porr
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
**/
#ifndef IIR_H
#define IIR_H
//
// Include this file in your application to get everything
//
#include "iir/Common.h"
#include "iir/Biquad.h"
#include "iir/Cascade.h"
#include "iir/PoleFilter.h"
#include "iir/State.h"
#include "iir/Butterworth.h"
#include "iir/ChebyshevI.h"
#include "iir/ChebyshevII.h"
#include "iir/Custom.h"
#include "iir/RBJ.h"
#endif

Wyświetl plik

@ -1,326 +0,0 @@
# DSP IIR Realtime C++ filter library
![alt tag](title.png)
- High performance
- Realtime sample in - sample out processing
- Butterworth, RBJ, Chebychev filters
- Lowpass, highpass, bandpass and bandstop filters
- Template based header-only filter functions
- Cross platform: Linux, Windows and Mac
An infinite impulse response (IIR) filter library for
Linux, Mac OSX and Windows
which implements Butterworth, RBJ, Chebychev filters
and can easily import coefficients generated by Python (scipy).
The filter processes the data sample by sample for realtime
processing.
It uses templates to allocate the required memory so that
it can run without any malloc / new commands.
Memory is allocated at compile time
so that there is never the risk of memory leaks.
All realtime filter code is in the header files which guarantees
efficient integration into the main program and the compiler
can optimise both filter code and main program at the same time.
## C++ code
Add the following include statement to your code:
```
#include "Iir.h"
```
The general coding approach is that first the filter is
instantiated specifying its order, then the
parameters are set with the function `setup` and
then it's ready to be used for sample by sample realtime filtering.
### Instantiating the filter
The idea is to allocate the memory of the
filter at compile time with a template argument to avoid any new
commands. This prevents memory leaks and can be optimised at compile
time. The `order` provided to the template (for example here for a
lowpass filter):
```
Iir::Butterworth::LowPass<order> f;
```
is used as the default order by the `setup` command below
but can be overridden by a lower order if required.
### Setting the filter parameters: `setup`
All filters are available as lowpass, highpass, bandpass and bandstop/notch
filters. Butterworth / Chebyshev offer also low/high/band-shelves with
specified passband gain and 0dB gain in the stopband.
The frequencies can either be analogue ones against the sampling rate
or normalised ones between 0..1/2 where 1/2 is the Nyquist frequency. Note
that normalised frequencies are simply f = F/Fs and are in units of 1/samples.
Internally the library uses normalised frequencies and the setup commands
simply divide by the sampling rate if given. Choose between:
1. `setup`: sampling rate and the analogue cutoff frequencies
2. `setupN`: normalised frequencies in 1/samples between f = 0..1/2 where 1/2 = Nyquist.
By default `setup` uses the order supplied by the template argument but
can be overridden by lower filter orders.
See the header files in `\iir` or the documentation for the arguments
of the `setup` commands.
The examples below are for lowpass filters:
1. Butterworth -- `Butterworth.h`
Standard filter suitable for most applications. Monotonic response.
```
const int order = 4; // 4th order (=2 biquads)
Iir::Butterworth::LowPass<order> f;
const float samplingrate = 1000; // Hz
const float cutoff_frequency = 5; // Hz
f.setup (samplingrate, cutoff_frequency);
```
or specify a normalised frequency between 0..1/2:
```
f.setupN(norm_cutoff_frequency);
```
2. Chebyshev Type I -- `ChebyshevI.h`
With permissible passband ripple in dB.
```
Iir::ChebyshevI::LowPass<order> f;
const float passband_ripple_in_db = 5;
f.setup (samplingrate,
cutoff_frequency,
passband_ripple_in_dB);
```
or specify a normalised frequency between 0..1/2:
```
f.setupN(norm_cutoff_frequency,passband_ripple_in_dB);
```
3. Chebyshev Type II -- `ChebyshevII.h`
With worst permissible stopband rejection in dB.
```
Iir::ChebyshevII::LowPass<order> f;
double stopband_ripple_in_dB = 20;
f.setup (samplingrate,
cutoff_frequency,
stopband_ripple_in_dB);
```
or specify a normalised frequency between 0..1/2:
```
f.setupN(norm_cutoff_frequency,stopband_ripple_in_dB);
```
4. RBJ -- `RBJ.h`
2nd order filters with cutoff and Q factor.
```
Iir::RBJ::LowPass f;
const float cutoff_frequency = 100;
const float Q_factor = 5;
f.setup (samplingrate, cutoff_frequency, Q_factor);
```
or specify a normalised frequency between 0..1/2:
```
f.setupN(norm_cutoff_frequency, Q_factor);
```
5. Designing filters with Python's scipy.signal -- `Custom.h`
```
########
# Python
# See "elliptic_design.py" for the complete code.
from scipy import signal
order = 4
sos = signal.ellip(order, 5, 40, 0.2, 'low', output='sos')
print(sos) # copy/paste the coefficients over & replace [] with {}
///////
// C++
// part of "iirdemo.cpp"
const double coeff[][6] = {
{1.665623674062209972e-02,
-3.924801366970616552e-03,
1.665623674062210319e-02,
1.000000000000000000e+00,
-1.715403014004022175e+00,
8.100474793174089472e-01},
{1.000000000000000000e+00,
-1.369778997100624895e+00,
1.000000000000000222e+00,
1.000000000000000000e+00,
-1.605878925999785656e+00,
9.538657786383895054e-01}
};
const int nSOS = sizeof(coeff) / sizeof(coeff[0]); // here: nSOS = 2 = order / 2
Iir::Custom::SOSCascade<nSOS> cust(coeff);
```
### Realtime filtering sample by sample
Samples are processed one by one. In the example below
a sample `x` is processed with the `filter`
command and then saved in `y`. The types of `x` and `y` can either be
float or double
(integer is also allowed but is still processed internally as floating point):
```
y = f.filter(x);
```
This is then repeated for every incoming sample in a
loop or event handler.
### Error handling
Invalid values provided to `setup()` will throw
an exception. Parameters provided to `setup()` which
result in coefficients being NAN will also
throw an exception.
## Linking
### CMake setup
If you use cmake as your build system then just add
to your `CMakeLists.txt` the following lines for the dynamic library:
```
find_package(iir)
target_link_libraries(... iir::iir)
```
or for the static one:
```
find_package(iir)
target_link_libraries(... iir::iir_static)
```
### Generic linker setup
Link it against the dynamic library
(Unix/Mac: `-liir`, Windows: `iir.lib`)
or the static library (Unix/Mac: `libiir_static.a`,
Windows: `libiir_static.lib`).
## Packages for Ubuntu (xenial / bionic / focal):
If you have Ubuntu's LTS distros xenial, bionic or focal then
install it as a pre-compiled package:
```
sudo add-apt-repository ppa:berndporr/dsp
```
It's available for 32,64 bit PC and 32,64 bit ARM (Raspberry PI etc).
The documentation and the example programs are in:
```
/usr/share/doc/iir1-dev/
```
## Package for MacOS
Make sure you have the homebrew package manager installed: https://brew.sh/
Add the homebrew tap:
```
brew tap berndporr/dsp
```
and then install the iir filter package with:
```
brew install iir
```
## Compilation from source
The build tool is `cmake` which generates the make- or project
files for the different platforms. `cmake` is available for
Linux, Windows and Mac. It also compiles directly on a
Raspberry PI.
### Linux / Mac
Run
```
cmake .
```
which generates the Makefile. Then run:
```
make
sudo make install
```
which installs it under `/usr/local/lib` and `/usr/local/include`.
Both gcc and clang have been tested.
### Windows
```
cmake -G "Visual Studio 16 2019" -A x64 .
```
See `cmake` for the different build-options. Above is for a 64 bit build.
Then start Visual C++ and open the solution. This will create
the DLL and the LIB files. Under Windows it's highly recommended
to use the static library and link it into the application program.
### Unit tests
Run unit tests by typing `make test` or just `ctest`.
These test if after a delta pulse all filters relax to zero,
that their outputs never become NaN and if the Direct Form I&II filters calculate
expected sequences by comparing them from results created
by the output of scipy's `sosfilt`.
## Documentation
### Learn from the demos
The easiest way to learn is from the examples which are in the `demo`
directory. A delta pulse as a test signal is sent into the different
filters and saved in a file. With the Python script
`plot_impulse_fresponse.py` you can then plot the frequency responses.
Also the directory containing the unit tests provides examples for
every filter type.
### Detailed documentation
A PDF of all classes, methods and in particular `setup` functions
is in the `docs/pdf` directory.
The online documentation is here: http://berndporr.github.io/iir1
## Example filter responses
These responses have been generated by `iirdemo.cpp`
in the `/demo/` directory and then plotted with `plot_impulse_fresponse.py`.
![alt tag](demo/1.png)
![alt tag](demo/2.png)
![alt tag](demo/3.png)
![alt tag](demo/4.png)
![alt tag](demo/5.png)
![alt tag](demo/7.png)
![alt tag](demo/8.png)
## Credits
This library has been further developed from Vinnie Falco's
great original work which can be found here:
https://github.com/vinniefalco/DSPFilters
While the original library processes audio arrays this
library has been adapted to do fast realtime processing sample
by sample. The `setup`
command won't require the filter order and instead remembers
it from the template argument. The class structure has
been simplified and all functions documented for doxygen.
Instead of having assert() statements this libary throws
exceptions in case a parameter is wrong. Any filter design
requiring optimisation (for example Ellipic filters) has
been removed and instead a function has been added which can import easily
coefficients from scipy.
Bernd Porr -- http://www.berndporr.me.uk

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 57 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 50 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 52 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 68 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 68 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 60 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 49 KiB

Wyświetl plik

@ -1,19 +0,0 @@
project(IIRDemo)
cmake_minimum_required(VERSION 3.1.0)
set(CMAKE_CXX_STANDARD 11)
if (MSVC)
add_compile_options(/W4 /WX)
else()
add_compile_options(-Wall -Wextra -pedantic -Werror)
endif()
add_executable (iirdemo iirdemo.cpp)
target_link_libraries(iirdemo iir_static)
target_include_directories(iirdemo PRIVATE ..)
add_executable (ecg50hzfilt ecg50hzfilt.cpp)
target_link_libraries(ecg50hzfilt iir_static)
target_include_directories(ecg50hzfilt PRIVATE ..)

Wyświetl plik

@ -1,27 +0,0 @@
# Coding examples
This demo directory shows how filters are set up, how data is
processed sample by sample and how the frequency responses
look like with the help of python scripts.
## Impulse responses and spectra of different filters:
```
./iirdemo
python3 plot_impulse_fresponse.py
```
## 50Hz removal and lowpass filtering:
```
./ecg50hzfilt
python3 plot_ecg_filt.py
```
## Optimisation tips
The actual filter operations are header-only which means that
they will never be pre-compiled in the library but the compiler
can optimise the filter routine for your local processor. Consider
using:
```
add_compile_options(-O3 -march=native)
```

Wyświetl plik

@ -1,21 +0,0 @@
#!/usr/bin/python3
# Calculates the coefficients for a Bessel filter
from scipy import signal
# sampling rate
fs = 1000
# cutoff
f0 = 100
# order
order = 8
sos = signal.bessel(order, f0/fs*2, 'low', output='sos')
for s in sos:
print("{",end="")
n = 0
for c in s:
print("%.18e" % c,end="")
n=n+1
if n<6:
print(",",end="")
print("},")

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 91 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 80 KiB

Some files were not shown because too many files have changed in this diff Show More