Skip to content

Commit cf01769

Browse files
committed
[Examples]: Add example app for choosing different (or multiple) VT object pools at runtime based on the VT server version
1 parent 2a50b14 commit cf01769

File tree

6 files changed

+355
-0
lines changed

6 files changed

+355
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ if(BUILD_EXAMPLES)
6969
add_subdirectory("examples/virtual_terminal/version3_object_pool")
7070
add_subdirectory("examples/virtual_terminal/aux_functions")
7171
add_subdirectory("examples/virtual_terminal/aux_inputs")
72+
add_subdirectory("examples/virtual_terminal/multiple_object_pools")
7273
add_subdirectory("examples/task_controller_client")
7374
add_subdirectory("examples/task_controller_server")
7475
add_subdirectory("examples/guidance")
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
project(vt_client_multiple_object_pools_example)
3+
4+
if(NOT BUILD_EXAMPLES)
5+
find_package(isobus REQUIRED)
6+
endif()
7+
find_package(Threads REQUIRED)
8+
9+
add_executable(VTClientMultiplePoolsExampleTarget main.cpp console_logger.cpp
10+
objectPoolObjects.h)
11+
12+
target_compile_features(VTClientMultiplePoolsExampleTarget PUBLIC cxx_std_11)
13+
set_target_properties(VTClientMultiplePoolsExampleTarget
14+
PROPERTIES CXX_EXTENSIONS OFF)
15+
16+
target_link_libraries(
17+
VTClientMultiplePoolsExampleTarget
18+
PRIVATE isobus::Isobus isobus::HardwareIntegration Threads::Threads
19+
isobus::Utility)
20+
21+
add_custom_command(
22+
TARGET VTClientMultiplePoolsExampleTarget
23+
POST_BUILD
24+
COMMENT "Copying object pools to build directory"
25+
COMMAND
26+
${CMAKE_COMMAND} -E copy
27+
${CMAKE_CURRENT_SOURCE_DIR}/../version3_object_pool/VT3TestPool.iop
28+
$<TARGET_FILE_DIR:VTClientMultiplePoolsExampleTarget>/VT3TestPool.iop
29+
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/window_masks.iop
30+
$<TARGET_FILE_DIR:VTClientMultiplePoolsExampleTarget>/window_masks.iop
31+
)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#include "isobus/isobus/can_stack_logger.hpp"
2+
3+
#include <iostream>
4+
5+
// A log sink for the CAN stack
6+
class CustomLogger : public isobus::CANStackLogger
7+
{
8+
public:
9+
void sink_CAN_stack_log(CANStackLogger::LoggingLevel level, const std::string &text) override
10+
{
11+
switch (level)
12+
{
13+
case LoggingLevel::Debug:
14+
{
15+
std::cout << "["
16+
<< "\033[1;36m"
17+
<< "Debug"
18+
<< "\033[0m"
19+
<< "]";
20+
}
21+
break;
22+
23+
case LoggingLevel::Info:
24+
{
25+
std::cout << "["
26+
<< "\033[1;32m"
27+
<< "Info"
28+
<< "\033[0m"
29+
<< "]";
30+
}
31+
break;
32+
33+
case LoggingLevel::Warning:
34+
{
35+
std::cout << "["
36+
<< "\033[1;33m"
37+
<< "Warn"
38+
<< "\033[0m"
39+
<< "]";
40+
}
41+
break;
42+
43+
case LoggingLevel::Error:
44+
{
45+
std::cout << "["
46+
<< "\033[1;31m"
47+
<< "Error"
48+
<< "\033[0m"
49+
<< "]";
50+
}
51+
break;
52+
53+
case LoggingLevel::Critical:
54+
{
55+
std::cout << "["
56+
<< "\033[1;35m"
57+
<< "Critical"
58+
<< "\033[0m"
59+
<< "]";
60+
}
61+
break;
62+
}
63+
std::cout << text << std::endl; // Write the text to stdout
64+
}
65+
};
66+
67+
static CustomLogger logger;
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
#include "isobus/hardware_integration/available_can_drivers.hpp"
2+
#include "isobus/hardware_integration/can_hardware_interface.hpp"
3+
#include "isobus/isobus/can_network_manager.hpp"
4+
#include "isobus/isobus/can_partnered_control_function.hpp"
5+
#include "isobus/isobus/can_stack_logger.hpp"
6+
#include "isobus/isobus/isobus_virtual_terminal_client.hpp"
7+
#include "isobus/isobus/isobus_virtual_terminal_client_update_helper.hpp"
8+
#include "isobus/utility/iop_file_interface.hpp"
9+
10+
#include "console_logger.cpp"
11+
#include "objectPoolObjects.h"
12+
13+
#include <atomic>
14+
#include <csignal>
15+
#include <iostream>
16+
17+
//! It is discouraged to use global variables, but it is done here for simplicity.
18+
static std::shared_ptr<isobus::VirtualTerminalClient> virtualTerminalClient = nullptr;
19+
static std::shared_ptr<isobus::VirtualTerminalClientUpdateHelper> virtualTerminalUpdateHelper = nullptr;
20+
static std::atomic_bool running = { true };
21+
22+
void signal_handler(int)
23+
{
24+
running = false;
25+
}
26+
27+
// This callback will provide us with event driven notifications of softkey presses from the stack
28+
void handle_softkey_event(const isobus::VirtualTerminalClient::VTKeyEvent &event)
29+
{
30+
if (event.keyNumber == 0)
31+
{
32+
// We have the alarm ACK code, so if we have an active alarm, acknowledge it by going back to the main runscreen
33+
virtualTerminalUpdateHelper->set_active_data_or_alarm_mask(example_WorkingSet, mainRunscreen_DataMask);
34+
}
35+
36+
switch (event.keyEvent)
37+
{
38+
case isobus::VirtualTerminalClient::KeyActivationCode::ButtonUnlatchedOrReleased:
39+
{
40+
switch (event.objectID)
41+
{
42+
case alarm_SoftKey:
43+
{
44+
virtualTerminalUpdateHelper->set_active_data_or_alarm_mask(example_WorkingSet, example_AlarmMask);
45+
}
46+
break;
47+
48+
case acknowledgeAlarm_SoftKey:
49+
{
50+
virtualTerminalUpdateHelper->set_active_data_or_alarm_mask(example_WorkingSet, mainRunscreen_DataMask);
51+
}
52+
break;
53+
54+
default:
55+
break;
56+
}
57+
}
58+
break;
59+
60+
default:
61+
break;
62+
}
63+
}
64+
65+
// This callback will provide us with event driven notifications of button presses from the stack
66+
void handle_button_event(const isobus::VirtualTerminalClient::VTKeyEvent &event)
67+
{
68+
switch (event.keyEvent)
69+
{
70+
case isobus::VirtualTerminalClient::KeyActivationCode::ButtonUnlatchedOrReleased:
71+
case isobus::VirtualTerminalClient::KeyActivationCode::ButtonStillHeld:
72+
{
73+
switch (event.objectID)
74+
{
75+
case Plus_Button:
76+
{
77+
virtualTerminalUpdateHelper->increase_numeric_value(ButtonExampleNumber_VarNum);
78+
}
79+
break;
80+
81+
case Minus_Button:
82+
{
83+
virtualTerminalUpdateHelper->decrease_numeric_value(ButtonExampleNumber_VarNum);
84+
}
85+
break;
86+
87+
default:
88+
break;
89+
}
90+
}
91+
break;
92+
93+
default:
94+
break;
95+
}
96+
}
97+
98+
int main()
99+
{
100+
std::signal(SIGINT, signal_handler);
101+
102+
// Automatically load the desired CAN driver based on the available drivers
103+
std::shared_ptr<isobus::CANHardwarePlugin> canDriver = nullptr;
104+
#if defined(ISOBUS_SOCKETCAN_AVAILABLE)
105+
canDriver = std::make_shared<isobus::SocketCANInterface>("can0");
106+
#elif defined(ISOBUS_WINDOWSPCANBASIC_AVAILABLE)
107+
canDriver = std::make_shared<isobus::PCANBasicWindowsPlugin>(PCAN_USBBUS1);
108+
#elif defined(ISOBUS_WINDOWSINNOMAKERUSB2CAN_AVAILABLE)
109+
canDriver = std::make_shared<isobus::InnoMakerUSB2CANWindowsPlugin>(0); // CAN0
110+
#elif defined(ISOBUS_MACCANPCAN_AVAILABLE)
111+
canDriver = std::make_shared<isobus::MacCANPCANPlugin>(PCAN_USBBUS1);
112+
#elif defined(ISOBUS_SYS_TEC_AVAILABLE)
113+
canDriver = std::make_shared<isobus::SysTecWindowsPlugin>();
114+
#endif
115+
if (nullptr == canDriver)
116+
{
117+
std::cout << "Unable to find a CAN driver. Please make sure you have one of the above drivers installed with the library." << std::endl;
118+
std::cout << "If you want to use a different driver, please add it to the list above." << std::endl;
119+
return -1;
120+
}
121+
122+
isobus::CANStackLogger::set_can_stack_logger_sink(&logger);
123+
isobus::CANStackLogger::set_log_level(isobus::CANStackLogger::LoggingLevel::Info); // Change this to Debug to see more information
124+
isobus::CANHardwareInterface::set_number_of_can_channels(1);
125+
isobus::CANHardwareInterface::assign_can_channel_frame_handler(0, canDriver);
126+
127+
if ((!isobus::CANHardwareInterface::start()) || (!canDriver->get_is_valid()))
128+
{
129+
std::cout << "Failed to start hardware interface. The CAN driver might be invalid." << std::endl;
130+
return -2;
131+
}
132+
133+
std::this_thread::sleep_for(std::chrono::milliseconds(250));
134+
135+
isobus::NAME TestDeviceNAME(0);
136+
137+
//! Make sure you change these for your device!!!!
138+
TestDeviceNAME.set_arbitrary_address_capable(true);
139+
TestDeviceNAME.set_industry_group(1);
140+
TestDeviceNAME.set_device_class(0);
141+
TestDeviceNAME.set_function_code(static_cast<std::uint8_t>(isobus::NAME::Function::SteeringControl));
142+
TestDeviceNAME.set_identity_number(2);
143+
TestDeviceNAME.set_ecu_instance(0);
144+
TestDeviceNAME.set_function_instance(0);
145+
TestDeviceNAME.set_device_class_instance(0);
146+
TestDeviceNAME.set_manufacturer_code(1407);
147+
148+
std::vector<std::uint8_t> version3pool = isobus::IOPFileInterface::read_iop_file("VT3TestPool.iop");
149+
std::vector<std::uint8_t> version4pool = isobus::IOPFileInterface::read_iop_file("window_masks.iop");
150+
151+
if (version3pool.empty())
152+
{
153+
std::cout << "Failed to load object pool from VT3TestPool.iop" << std::endl;
154+
return -3;
155+
}
156+
std::cout << "Loaded object pool from VT3TestPool.iop" << std::endl;
157+
158+
if (version4pool.empty())
159+
{
160+
std::cout << "Failed to load object pool from window_masks.iop" << std::endl;
161+
return -4;
162+
}
163+
std::cout << "Loaded object pool from window_masks.iop" << std::endl;
164+
165+
// Generate a unique version string for this object pool (this is optional, and is entirely application specific behavior)
166+
std::string objectPoolHash = "";
167+
168+
const isobus::NAMEFilter filterVirtualTerminal(isobus::NAME::NAMEParameters::FunctionCode, static_cast<std::uint8_t>(isobus::NAME::Function::VirtualTerminal));
169+
const std::vector<isobus::NAMEFilter> vtNameFilters = { filterVirtualTerminal };
170+
auto TestInternalECU = isobus::CANNetworkManager::CANNetwork.create_internal_control_function(TestDeviceNAME, 0);
171+
auto TestPartnerVT = isobus::CANNetworkManager::CANNetwork.create_partnered_control_function(0, vtNameFilters);
172+
173+
virtualTerminalClient = std::make_shared<isobus::VirtualTerminalClient>(TestPartnerVT, TestInternalECU);
174+
virtualTerminalClient->get_vt_soft_key_event_dispatcher().add_listener(handle_softkey_event);
175+
virtualTerminalClient->get_vt_button_event_dispatcher().add_listener(handle_button_event);
176+
virtualTerminalClient->set_on_ready_for_object_pool_callback([&version3pool, &version4pool, objectPoolHash](isobus::VirtualTerminalClient::VTVersion version) {
177+
// You can check the connected VT version if you need to know what features are available, and select which object pool(s) to use based on that.
178+
// This is optional though. If you want, you can just call set_object_pool() blindly exactly one time at any point if you want to try to use the same object pool for all VT versions.
179+
switch (virtualTerminalClient->get_connected_vt_version())
180+
{
181+
case isobus::VirtualTerminalClient::VTVersion::Version3:
182+
{
183+
// For version 3, we upload a base pool with only VT version 3 complaint objects
184+
virtualTerminalClient->set_object_pool(0, version3pool.data(), version3pool.size(), objectPoolHash);
185+
}
186+
break;
187+
188+
case isobus::VirtualTerminalClient::VTVersion::Version4:
189+
case isobus::VirtualTerminalClient::VTVersion::Version5:
190+
case isobus::VirtualTerminalClient::VTVersion::Version6:
191+
{
192+
// For version 4, 5, and 6, we upload the same base pool as version 3, but also upload a second pool with version 4 objects
193+
virtualTerminalClient->set_object_pool(0, version3pool.data(), version3pool.size(), objectPoolHash);
194+
virtualTerminalClient->set_object_pool(1, version4pool.data(), version4pool.size(), objectPoolHash);
195+
}
196+
break;
197+
198+
default:
199+
{
200+
// Either we're not ready yet, or we don't have an object pool for this version
201+
}
202+
break;
203+
}
204+
});
205+
virtualTerminalClient->initialize(true);
206+
207+
virtualTerminalUpdateHelper = std::make_shared<isobus::VirtualTerminalClientUpdateHelper>(virtualTerminalClient);
208+
virtualTerminalUpdateHelper->add_tracked_numeric_value(ButtonExampleNumber_VarNum, 214748364); // In the object pool the output number has an offset of -214748364 so we use this to represent 0.
209+
virtualTerminalUpdateHelper->initialize();
210+
211+
while (running)
212+
{
213+
// CAN stack runs in other threads. Do nothing forever.
214+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
215+
}
216+
217+
virtualTerminalClient->terminate();
218+
isobus::CANHardwareInterface::stop();
219+
return 0;
220+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// This is a file that will be auto-generated by your object pool designer application.
2+
// These are the object IDs for the objects in the object pool
3+
#define UNDEFINED 65535 //0xFFFF
4+
#define example_WorkingSet 0 //0x0000
5+
#define mainRunscreen_DataMask 1000 //0x03E8
6+
#define example_AlarmMask 2000 //0x07D0
7+
#define exampleNumberInc_Container 3000 //0x0BB8
8+
#define mainRunscreen_SoftKeyMask 4000 //0x0FA0
9+
#define alarm_SKeyMask 4001 //0x0FA1
10+
#define alarm_SoftKey 5000 //0x1388
11+
#define acknowledgeAlarm_SoftKey 5001 //0x1389
12+
#define Plus_Button 6000 //0x1770
13+
#define Minus_Button 6001 //0x1771
14+
#define Title_OutStr 11000 //0x2AF8
15+
#define MainDescription_OutStr 11001 //0x2AF9
16+
#define temp_OutStr_ID_11002 11002 //0x2AFA
17+
#define temp_OutStr_ID_11003 11003 //0x2AFB
18+
#define AlarmMaskTitle_OutStr 11004 //0x2AFC
19+
#define exampleOutput_OutNum 12000 //0x2EE0
20+
#define Title_OutRect 14000 //0x36B0
21+
#define MainRunscreenBackground_OutRect 14001 //0x36B1
22+
#define avatar_OutPict 20000 //0x4E20
23+
#define warningIcon_OutPict 20001 //0x4E21
24+
#define redAlert_OutPict 20002 //0x4E22
25+
#define greenCheck_OutPict 20003 //0x4E23
26+
#define ButtonExampleNumber_VarNum 21000 //0x5208
27+
#define title_OutStr 22000 //0x55F0
28+
#define MainDescription_VarStr 22001 //0x55F1
29+
#define alarmMaskTitle_OutStr 22002 //0x55F2
30+
#define ExampleAlarmMask_VarStr 22003 //0x55F3
31+
#define temp_FontAttr_ID_23000 23000 //0x59D8
32+
#define temp_FontAttr_ID_23001 23001 //0x59D9
33+
#define black48x64_FontAttr 23002 //0x59DA
34+
#define solidBlack_LineAttr 24000 //0x5DC0
35+
#define solidWhite_FillAttr 25000 //0x61A8
36+
#define exampleNumberInc_ObjPtr 27000 //0x6978
55 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)