A2B: Add additional examples

Device: Add coremini loading example
pull/56/head
Yasser Yassine 2023-04-12 16:29:48 +00:00
parent 63c81b1c3d
commit 3ddb832708
8 changed files with 188 additions and 62 deletions

1
.gitignore vendored
View File

@ -10,3 +10,4 @@ third-party/concurrentqueue/tests
*.bak *.bak
.vs .vs
.cache .cache
*.wav

View File

@ -69,7 +69,7 @@ A2BDecoder::A2BDecoder(
) : A2BDecoder(std::make_unique<std::ifstream>(filename, std::ios::binary), chSize16, chMap) { } ) : A2BDecoder(std::make_unique<std::ifstream>(filename, std::ios::binary), chSize16, chMap) { }
A2BDecoder::operator bool() const { A2BDecoder::operator bool() const {
return initialized && *stream; return initialized && stream->good() && !stream->eof();
} }
void A2BDecoder::initializeFromHeader() { void A2BDecoder::initializeFromHeader() {

View File

@ -5,6 +5,8 @@ option(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE "Build the simple C++ example." ON)
option(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON) option(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON)
option(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE "Build the A2B example." ON) option(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE "Build the A2B example." ON)
option(LIBICSNEO_BUILD_CPP_LIN_EXAMPLE "Build the LIN example." ON) option(LIBICSNEO_BUILD_CPP_LIN_EXAMPLE "Build the LIN example." ON)
option(LIBICSNEO_BUILD_CPP_COREMINI_EXAMPLE "Build the Coremini example." ON)
# Disabled until we properly build these in-tree # Disabled until we properly build these in-tree
# option(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE "Build the command-line interactive C# example." OFF) # option(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE "Build the command-line interactive C# example." OFF)
# option(LIBICSNEO_BUILD_JAVA_INTERACTIVE_EXAMPLE "Build the command-line interactive Java example." OFF) # option(LIBICSNEO_BUILD_JAVA_INTERACTIVE_EXAMPLE "Build the command-line interactive Java example." OFF)
@ -36,6 +38,11 @@ endif()
if(LIBICSNEO_BUILD_CPP_LIN_EXAMPLE) if(LIBICSNEO_BUILD_CPP_LIN_EXAMPLE)
add_subdirectory(cpp/lin) add_subdirectory(cpp/lin)
endif() endif()
if(LIBICSNEO_BUILD_CPP_COREMINI_EXAMPLE)
add_subdirectory(cpp/coremini)
endif()
# if(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE) # if(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE)
# add_subdirectory(csharp) # add_subdirectory(csharp)
# endif() # endif()

View File

@ -1,48 +0,0 @@
# libicsneo C++ Example
This is an example console application which uses libicsneo to connect to an Intrepid Control Systems hardware device. It has both interactive and simple examples for sending and receiving CAN & CAN FD traffic.
## Building
This example shows how to use the C++ version of libicsneo with CMake. It will build libicsneo along with your project.
First, you need to clone the repository onto your local machine. Run:
```shell
git clone https://github.com/intrepidcs/libicsneo-examples --recursive
```
Alternatively, if you cloned without the `--recursive flag`, you must enter the `libicsneo-examples` folder and run the following:
```shell
git submodule update --recursive --init
```
If you haven't done this, `third-party/libicsneo` will be empty and you won't be able to build!
### Windows using Visual Studio 2017+
1. Launch Visual Studio and open the `libicsneo-examples` folder.
2. Choose `File->Open->CMake...`
3. Navigate to the `libicsneocpp-example` folder and select the `CMakeLists.txt` there.
4. Visual Studio will process the CMake project.
5. Choose the dropdown attached to the green play button (labelled "select startup item...") in the toolbar.
6. Select `libicsneocpp-simple-example.exe`
7. Press the green play button to compile and run the example.
### Ubuntu 18.04 LTS
1. Install dependencies with `sudo apt update` then `sudo apt install build-essential cmake libusb-1.0-0-dev libpcap0.8-dev`
2. Change directories to your `libicsneo-examples/libicsneocpp-example` folder and create a build directory by running `mkdir -p build`
3. Enter the build directory with `cd build`
4. Run `cmake ..` to generate your Makefile.
* Hint! Running `cmake -DCMAKE_BUILD_TYPE=Debug ..` will generate the proper scripts to build debug, and `cmake -DCMAKE_BUILD_TYPE=Release ..` will generate the proper scripts to build with all optimizations on.
5. Run `make libicsneocpp-interactive-example` to build.
* Hint! Speed up your build by using multiple processors! Use `make libicsneocpp-interactive-example -j#` where `#` is the number of cores/threads your system has plus one. For instance, on a standard 8 thread Intel i7, you might use `-j9` for an ~8x speedup.
6. Now run `sudo ./libicsneocpp-interactive-example` to run the example.
* Hint! In order to run without sudo, you will need to set up the udev rules. Copy `libicsneo-examples/third-party/libicsneo/99-intrepidcs.rules` to `/etc/udev/rules.d`, then run `udevadm control --reload-rules && udevadm trigger` afterwards. While the program will still run without setting up these rules, it will fail to open any devices.
7. If you wish to run the simple example instead, replace any instances of "interactive" with "simple" in steps 5 and 6.
### macOS
Instructions coming soon&trade;

View File

@ -12,6 +12,7 @@
#include <icsneo/device/tree/rada2b/rada2bsettings.h> #include <icsneo/device/tree/rada2b/rada2bsettings.h>
#include <icsneo/communication/message/callback/streamoutput/a2bdecoder.h> #include <icsneo/communication/message/callback/streamoutput/a2bdecoder.h>
#include <string> #include <string>
#include <math.h>
static constexpr size_t numFramesInWave = 48; static constexpr size_t numFramesInWave = 48;
@ -70,7 +71,7 @@ void example0(std::shared_ptr<icsneo::Device>& rada2b) {
decoder.outputAll(rada2b); // Output entire wave file decoder.outputAll(rada2b); // Output entire wave file
elapsedTime += ((double)numFramesInWave) * 1.0/48000.0; elapsedTime += (static_cast<double>(numFramesInWave)) * 1.0/48000.0;
decoder.stream->clear(); decoder.stream->clear();
decoder.stream->seekg(0, std::ios::beg); decoder.stream->seekg(0, std::ios::beg);
@ -78,7 +79,7 @@ void example0(std::shared_ptr<icsneo::Device>& rada2b) {
while(decoder && elapsedTime < 5.0) { while(decoder && elapsedTime < 5.0) {
auto msg = decoder.decode(); auto msg = decoder.decode();
rada2b->transmit(msg); rada2b->transmit(msg);
elapsedTime += ((double)msg->getNumFrames())*1.0/48000.0; elapsedTime += (static_cast<double>(msg->getNumFrames()))*1.0/48000.0;
} }
decoder.stream->clear(); decoder.stream->clear();
@ -105,11 +106,11 @@ void example1(std::shared_ptr<icsneo::Device>& rada2b) {
// Example 2: RADA2B settings // Example 2: RADA2B settings
void example2(std::shared_ptr<icsneo::Device>& rada2b) { void example2(std::shared_ptr<icsneo::Device>& rada2b) {
uint32_t tdm; uint8_t numChannels;
{ {
// Get device settings // Get device settings
auto* settings = rada2b->settings.get(); auto* settings = rada2b->settings.get();
auto* rada2bSettings = (icsneo::RADA2BSettings*)settings; auto* rada2bSettings = static_cast<icsneo::RADA2BSettings*>(settings);
// Check if monitor mode is enabled // Check if monitor mode is enabled
auto type = rada2bSettings->getNodeType(icsneo::RADA2BSettings::RADA2BDevice::Monitor); auto type = rada2bSettings->getNodeType(icsneo::RADA2BSettings::RADA2BDevice::Monitor);
@ -121,9 +122,9 @@ void example2(std::shared_ptr<icsneo::Device>& rada2b) {
} }
// Get current tdm mode // Get current tdm mode
tdm = rada2bSettings->getTDMModeInt(icsneo::RADA2BSettings::RADA2BDevice::Node); numChannels = rada2bSettings->getNumChannels(icsneo::RADA2BSettings::RADA2BDevice::Node);
std::cout << "Current tdm mode: " << tdm << std::endl; std::cout << "Current num channels: " << static_cast<uint32_t>(numChannels) << std::endl;
// Set node type to master node. // Set node type to master node.
rada2bSettings->setNodeType(icsneo::RADA2BSettings::RADA2BDevice::Node, icsneo::RADA2BSettings::NodeType::Master); rada2bSettings->setNodeType(icsneo::RADA2BSettings::RADA2BDevice::Node, icsneo::RADA2BSettings::NodeType::Master);
@ -174,6 +175,68 @@ void example3() {
std::cout << "Was received from monitor: " << msg.isMonitorMsg() << std::endl; std::cout << "Was received from monitor: " << msg.isMonitorMsg() << std::endl;
} }
// Example 4: Packaging and transmitting sine wave using A2BMessage API
void example4(std::shared_ptr<icsneo::Device>& rada2b) {
std::cout << "Transmitting a 1000 hz sine wave." << std::endl;
float deltaTime = static_cast<float>(1.0/48000.0);
float elapsedTime = 0.0;
float twoPI = static_cast<float>(2.0*atan(1.0)*4.0);
float frequency = 1000;
float amplitude = static_cast<float>((1 << 23) - 1);
uint8_t icsChannel = 0; // Play audio on channel 2, upstream, see docs for details
// Play for roughly 5 seconds
while(elapsedTime < 5.0) {
// Allocate message
std::shared_ptr<icsneo::A2BMessage> a2bmsgPtr = std::make_shared<icsneo::A2BMessage>(static_cast<uint8_t>(4), false, static_cast<size_t>(2048));
icsneo::A2BMessage& a2bmsg = *a2bmsgPtr.get();
a2bmsg.network = icsneo::Network(icsneo::Network::NetID::A2B2);
for(size_t frame = 0; frame < a2bmsg.getNumFrames(); frame++) {
// Sine wave sample, amplitude 1000, frequency 1000 hz
float contSample = amplitude*sin(twoPI*frequency*elapsedTime);
icsneo::A2BPCMSample sample = static_cast<icsneo::A2BPCMSample>(contSample);
// Set sample for each frame in message
a2bmsg[frame][icsChannel] = sample;
elapsedTime+=deltaTime;
}
// Transmit message to device
if(!rada2b->transmit(a2bmsgPtr)) {
std::cout << "Failed to transmit." << std::endl;
}
}
}
// Example 5: Wave loop back
void example5(std::shared_ptr<icsneo::Device>& rada2b) {
auto listener = [&rada2b]() {
auto handler = rada2b->addMessageCallback(std::make_shared<icsneo::A2BWAVOutput>("looped.wav", 48000));
std::this_thread::sleep_for(std::chrono::seconds(5));
rada2b->removeMessageCallback(handler);
};
// Listen on another thread
std::thread listenerThread{listener};
// Transmit wave file using example0
example0(rada2b);
listenerThread.join();
}
void displayUsage() { void displayUsage() {
std::cout << "libicsneo A2B example" << std::endl; std::cout << "libicsneo A2B example" << std::endl;
@ -187,8 +250,10 @@ void displayUsage() {
std::cout << "Example options:" << std::endl; std::cout << "Example options:" << std::endl;
std::cout << "0\ttx" << std::endl; std::cout << "0\ttx" << std::endl;
std::cout << "1\trx" << std::endl; std::cout << "1\trx" << std::endl;
std::cout << "2\trx split channel" << std::endl; std::cout << "2\tSet RADA2B settings" << std::endl;
std::cout << "3\tA2BMessage API" << std::endl; std::cout << "3\tA2BMessage API" << std::endl;
std::cout << "4\tPackaging and transmitting sine wave using A2BMessage API" << std::endl;
std::cout << "5\tWave loopback" << std::endl;
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -212,7 +277,7 @@ int main(int argc, char **argv) {
int option = atoi(arguments[2].c_str()); int option = atoi(arguments[2].c_str());
if(option < 0 || option > 3) { if(option < 0 || option > 5) {
std::cerr << "Invalid usage." << std::endl; std::cerr << "Invalid usage." << std::endl;
displayUsage(); displayUsage();
return EXIT_FAILURE; return EXIT_FAILURE;
@ -274,6 +339,12 @@ int main(int argc, char **argv) {
case 3: case 3:
example3(); example3();
break; break;
case 4:
example4(rada2b);
break;
case 5:
example5(rada2b);
break;
default: default:
break; break;
} }

View File

@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.2)
project(libicsneocpp-coremini VERSION 0.2.0)
set(CMAKE_CXX_STANDARD_REQUIRED 11)
include(GNUInstallDirs)
# Add an include directory like so if desired
#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
# Enable Warnings
if(MSVC)
# Force to always compile with W4
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
endif()
# Add libicsneo, usually a git submodule within your project works well
#add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../third-party/libicsneo ${CMAKE_CURRENT_BINARY_DIR}/third-party/libicsneo)
add_executable(libicsneocpp-coremini src/coremini.cpp)
target_link_libraries(libicsneocpp-coremini icsneocpp)

View File

@ -0,0 +1,68 @@
// Usage:
// ./libicsneocpp-coremini [DEVICE_SERIAL] [COREMINI_SCRIPT_PATH]
#include <iostream>
#include <fstream>
#include <icsneo/icsneocpp.h>
void displayUsage() {
std::cout << "Usage:\n";
std::cout << "./libicsneocpp-coremini [DEVICE_SERIAL] [COREMINI_SCRIPT_PATH]\n";
}
int main(int argc, char** argv) {
std::vector<std::string> arguments(argv, argv + argc);
if(arguments.size() != 3) {
displayUsage();
return EXIT_FAILURE;
}
std::cout << icsneo::GetVersion() << std::endl;
const auto& devices = icsneo::FindAllDevices();
auto it = std::find_if(
devices.begin(),
devices.end(),
[&arguments](const auto &d)
{ return d->getSerial() == arguments[1]; });
if(it == devices.end()) {
std::cout << "Failed to find device." << std::endl;
return EXIT_FAILURE;
}
std::shared_ptr<icsneo::Device> device = *it;
if(!device->open()) {
std::cout << "Failed to open device." << std::endl;
std::cout << icsneo::GetLastError() << std::endl;
return EXIT_FAILURE;
}
if(!device->goOnline()) {
std::cout << "Failed to go online." << std::endl;
std::cout << icsneo::GetLastError() << std::endl;
return EXIT_FAILURE;
}
if (!device->uploadCoremini(std::make_unique<std::ifstream>(arguments[2], std::ios::binary), icsneo::Disk::MemoryType::Flash))
{
std::cout << "Failed to upload coremini" << std::endl;
std::cout << icsneo::GetLastError() << std::endl;
}
if (!device->startScript(icsneo::Disk::MemoryType::Flash))
{
std::cout << "Failed to start script" << std::endl;
std::cout << icsneo::GetLastError() << std::endl;
}
device->goOffline();
device->close();
return 0;
}

View File

@ -125,10 +125,10 @@ public:
auto cfg = getStructurePointer<rada2b_settings_t>(); auto cfg = getStructurePointer<rada2b_settings_t>();
auto &deviceSettings = device == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node; auto &deviceSettings = device == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node;
return (TDMMode)(deviceSettings.tdmMode); return static_cast<TDMMode>(deviceSettings.tdmMode);
} }
uint8_t getTDMModeInt(RADA2BDevice device) const { uint8_t getNumChannels(RADA2BDevice device) const {
return tdmModeToChannelNum(getTDMMode(device)); return tdmModeToChannelNum(getTDMMode(device));
} }
@ -136,7 +136,7 @@ public:
auto cfg = getStructurePointer<rada2b_settings_t>(); auto cfg = getStructurePointer<rada2b_settings_t>();
auto &deviceSettings = device == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node; auto &deviceSettings = device == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node;
return (ChannelSize)(~(deviceSettings.flags & a2bSettingsFlag16bit)); return static_cast<ChannelSize>(~(deviceSettings.flags & a2bSettingsFlag16bit));
} }
uint8_t getChannelOffset(RADA2BDevice device, A2BMessage::A2BDirection dir) const { uint8_t getChannelOffset(RADA2BDevice device, A2BMessage::A2BDirection dir) const {
@ -154,7 +154,7 @@ public:
auto cfg = getStructurePointer<rada2b_settings_t>(); auto cfg = getStructurePointer<rada2b_settings_t>();
auto &deviceSettings = device == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node; auto &deviceSettings = device == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node;
return (NodeType)(deviceSettings.nodeType); return static_cast<NodeType>(deviceSettings.nodeType);
} }
void setNodeType(RADA2BDevice device, NodeType newType) { void setNodeType(RADA2BDevice device, NodeType newType) {