11 Commits
87 changed files with 2886 additions and 1938 deletions
-24
View File
@@ -35,30 +35,6 @@ unit_test windows/x64:
- libicsneo-win-x64 - libicsneo-win-x64
timeout: 5m timeout: 5m
build windows/x86:
stage: build
script:
- cmd /C ci\build-windows32.bat
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- libicsneo-win-x64
unit_test windows/x86:
stage: unit_test
script:
- build\libicsneo-unit-tests.exe
dependencies:
- build windows/x86
needs:
- build windows/x86
tags:
- libicsneo-win-x64
timeout: 5m
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Ubuntu # Ubuntu
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
+3 -1
View File
@@ -82,7 +82,7 @@ if(MSVC)
add_definitions(-D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING) add_definitions(-D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING)
add_definitions(-D_ITERATOR_DEBUG_LEVEL=0) add_definitions(-D_ITERATOR_DEBUG_LEVEL=0)
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(LIBICSNEO_COMPILER_WARNINGS -Wall -Wno-switch -Wno-unknown-pragmas) set(LIBICSNEO_COMPILER_WARNINGS -Wall -Wno-unknown-pragmas)
endif() endif()
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
@@ -235,6 +235,7 @@ set(SRC_FILES
communication/message/networkmutexmessage.cpp communication/message/networkmutexmessage.cpp
communication/message/clientidmessage.cpp communication/message/clientidmessage.cpp
communication/message/transmitmessage.cpp communication/message/transmitmessage.cpp
communication/message/spiportkeymessage.cpp
communication/packet/flexraypacket.cpp communication/packet/flexraypacket.cpp
communication/packet/canpacket.cpp communication/packet/canpacket.cpp
communication/packet/a2bpacket.cpp communication/packet/a2bpacket.cpp
@@ -345,6 +346,7 @@ add_library(icsneocpp
api/icsneocpp/icsneocpp.cpp api/icsneocpp/icsneocpp.cpp
api/icsneocpp/event.cpp api/icsneocpp/event.cpp
api/icsneocpp/eventmanager.cpp api/icsneocpp/eventmanager.cpp
api/icsneocpp/heartbeat.cpp
api/icsneocpp/version.cpp api/icsneocpp/version.cpp
${SRC_FILES} ${SRC_FILES}
) )
+1
View File
@@ -45,6 +45,7 @@ Instructions for installing each API can be found in its respective documentatio
- RAD-Pluto - RAD-Pluto
- RAD-Star 2 - RAD-Star 2
- RAD-SuperMoon - RAD-SuperMoon
- RAD-wBMS
- ValueCAN 3 - ValueCAN 3
- ValueCAN 4 - ValueCAN 4
+20 -11
View File
@@ -5,6 +5,7 @@
#include "icsneo/device/devicefinder.h" #include "icsneo/device/devicefinder.h"
#include "icsneo/icsneocpp.h" #include "icsneo/icsneocpp.h"
#include "icsneo/communication/io.h" #include "icsneo/communication/io.h"
#include "icsneo/communication/network.h"
#include <string> #include <string>
#include <vector> #include <vector>
@@ -465,11 +466,13 @@ icsneoc2_error_t icsneoc2_device_pcb_serial_get(const icsneoc2_device_t* device,
return icsneoc2_error_invalid_type; return icsneoc2_error_invalid_type;
} }
const auto& data = *pcbSerial; const auto& data = *pcbSerial;
if(value) { if(!value) {
size_t copyLen = std::min(*value_length, data.size()); *value_length = data.size();
std::copy(data.begin(), data.begin() + copyLen, value); return icsneoc2_error_success;
} }
*value_length = data.size(); size_t copyLen = std::min(*value_length, data.size());
std::copy(data.begin(), data.begin() + copyLen, value);
*value_length = copyLen;
return icsneoc2_error_success; return icsneoc2_error_success;
} }
@@ -503,26 +506,32 @@ icsneoc2_error_t icsneoc2_device_mac_addresses_enumerate(const icsneoc2_device_t
} }
tail = node; tail = node;
} }
*mac_entries = head;
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_mac_network_id_get(const icsneoc2_mac_addr_entry_t* mac_address, _icsneoc2_netid_t* network_id) { icsneoc2_error_t icsneoc2_mac_network_id_get(const icsneoc2_mac_addr_entry_t* mac_address, icsneoc2_netid_t* network_id) {
if(!mac_address || !network_id) { if(!mac_address || !network_id) {
return icsneoc2_error_invalid_parameters; return icsneoc2_error_invalid_parameters;
} }
*network_id = static_cast<_icsneoc2_netid_t>(mac_address->network_id); const auto netid = static_cast<Network::NetID>(mac_address->network_id);
*network_id = Network::GetCoreMiniNetworkFromNetID(netid).has_value()
? mac_address->network_id
: static_cast<icsneoc2_netid_t>(icsneoc2_netid_invalid);
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_mac_address_get(const icsneoc2_mac_addr_entry_t* mac_address, uint8_t* value, size_t* value_length) { icsneoc2_error_t icsneoc2_mac_address_get(const icsneoc2_mac_addr_entry_t* mac_address, uint8_t* value, size_t* value_length) {
if(!mac_address || !value || !value_length) { if(!mac_address || !value_length) {
return icsneoc2_error_invalid_parameters; return icsneoc2_error_invalid_parameters;
} }
if(value) { if(!value) {
size_t copyLen = std::min(*value_length, static_cast<size_t>(ICSNEO_MAC_ADDRESS_LEN)); *value_length = static_cast<size_t>(ICSNEO_MAC_ADDRESS_LEN);
std::copy(mac_address->address, mac_address->address + copyLen, value); return icsneoc2_error_success;
} }
*value_length = static_cast<size_t>(ICSNEO_MAC_ADDRESS_LEN); size_t copyLen = std::min(*value_length, static_cast<size_t>(ICSNEO_MAC_ADDRESS_LEN));
std::copy(mac_address->address, mac_address->address + copyLen, value);
*value_length = copyLen;
return icsneoc2_error_success; return icsneoc2_error_success;
} }
+5
View File
@@ -48,6 +48,11 @@ typedef struct icsneoc2_chip_versions_t {
icsneoc2_chip_versions_t* next; icsneoc2_chip_versions_t* next;
} icsneoc2_chip_versions_t; } icsneoc2_chip_versions_t;
typedef struct icsneoc2_termination_group_t {
std::vector<icsneoc2_netid_t> netids;
icsneoc2_termination_group_t* next;
} icsneoc2_termination_group_t;
typedef struct icsneoc2_mac_addr_entry_t { typedef struct icsneoc2_mac_addr_entry_t {
uint16_t network_id; uint16_t network_id;
uint8_t address[ICSNEO_MAC_ADDRESS_LEN]; uint8_t address[ICSNEO_MAC_ADDRESS_LEN];
+76
View File
@@ -179,6 +179,82 @@ icsneoc2_error_t icsneoc2_settings_termination_set(icsneoc2_device_t* device, ic
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_settings_termination_groups_enumerate(icsneoc2_device_t* device, icsneoc2_termination_group_t** groups, size_t* count) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!groups) {
return icsneoc2_error_invalid_parameters;
}
auto termination_groups = device->device->settings->getTerminationGroups();
icsneoc2_termination_group_t* head = nullptr;
icsneoc2_termination_group_t* tail = nullptr;
for(const auto& group : termination_groups) {
auto* node = new (std::nothrow) icsneoc2_termination_group_t;
if(!node) {
icsneoc2_settings_termination_groups_free(head);
return icsneoc2_error_out_of_memory;
}
node->netids.reserve(group.size());
for(const auto& network : group) {
node->netids.push_back(static_cast<icsneoc2_netid_t>(network.getNetID()));
}
node->next = nullptr;
if(!head) {
head = node;
} else {
tail->next = node;
}
tail = node;
}
*groups = head;
if(count) {
*count = termination_groups.size();
}
return icsneoc2_error_success;
}
icsneoc2_termination_group_t* icsneoc2_termination_group_next(const icsneoc2_termination_group_t* group) {
if(!group) {
return nullptr;
}
return group->next;
}
icsneoc2_error_t icsneoc2_termination_group_networks_get(const icsneoc2_termination_group_t* group, icsneoc2_netid_t* networks, size_t* count) {
if(!group || !count) {
return icsneoc2_error_invalid_parameters;
}
if(!networks) {
*count = group->netids.size();
return icsneoc2_error_success;
}
size_t to_copy = std::min<size_t>(*count, group->netids.size());
for(size_t i = 0; i < to_copy; i++) {
networks[i] = group->netids[i];
}
*count = to_copy;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_termination_groups_free(icsneoc2_termination_group_t* groups) {
if(!groups) {
return icsneoc2_error_invalid_parameters;
}
while(groups) {
auto* next = groups->next;
delete groups;
groups = next;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_commander_resistor_enabled(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* enabled) { icsneoc2_error_t icsneoc2_settings_commander_resistor_enabled(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* enabled) {
// Make sure the device is valid // Make sure the device is valid
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
+2
View File
@@ -462,6 +462,8 @@ const char* APIEvent::DescriptionForType(Type type) {
return TOO_MANY_EVENTS; return TOO_MANY_EVENTS;
case Type::Unknown: case Type::Unknown:
return UNKNOWN; return UNKNOWN;
case Type::Any:
break;
} }
return INVALID; return INVALID;
} }
+53
View File
@@ -0,0 +1,53 @@
#include "icsneo/api/heartbeat.h"
#include "icsneo/api/lifetime.h"
#include "icsneo/device/device.h"
using namespace icsneo;
Heartbeat::Heartbeat(Device& device) :
device(device), mode(device.isOnline() ? Mode::Passive : Mode::Active), thread(&Heartbeat::run, this) {
}
Heartbeat::~Heartbeat() {
{
std::lock_guard lk(mutex);
stop = true;
}
cv.notify_one();
thread.join();
}
void Heartbeat::run() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
auto filter = std::make_shared<MessageFilter>(Message::Type::ResetStatus);
bool status = false;
auto cbHandle = device.com->addMessageCallback(std::make_shared<MessageCallback>(filter, [&](std::shared_ptr<Message>) {
{
std::lock_guard lk(mutex);
status = true;
}
cv.notify_one();
}));
Lifetime cbLifetime([&] {
device.com->removeMessageCallback(cbHandle);
});
while(true) {
std::unique_lock lk(mutex);
if(mode == Mode::Active) {
if(cv.wait_for(lk, std::chrono::milliseconds(100), [&] { return stop; })) {
break;
}
device.com->sendCommand(Command::RequestStatusUpdate);
}
if(!cv.wait_for(lk, std::chrono::seconds(2), [&] { return status || stop; })) {
// we disconnect instead of close because it indicates to the user that a cleanup is still required (our thread join)
device.report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
device.com->driver->setIsDisconnected(true);
break;
}
if(stop)
break;
status = false;
}
}
@@ -5,6 +5,13 @@
#include <windows.h> #include <windows.h>
#include "icsneo/icsnVC40.h" #include "icsneo/icsnVC40.h"
// Vehicle Spy 3.26.3.9 removed these legacy settings structure definitions from
// icsnVC40.h. The corresponding functions only ever treat them as opaque
// buffers, so forward declarations keep the existing API/ABI intact.
typedef struct _SFireSettings SFireSettings;
typedef struct _SVCAN3Settings SVCAN3Settings;
typedef struct _SVCANRFSettings SVCANRFSettings;
bool LoadDLLAPI(HINSTANCE &hAPIDLL); bool LoadDLLAPI(HINSTANCE &hAPIDLL);
+11 -9
View File
@@ -1035,10 +1035,10 @@ int LegacyDLLExport icsneoGetDeviceSettingsType(void* hObject, EPlasmaIonVnetCha
case NEODEVICE_ION: case NEODEVICE_ION:
*pDeviceSettingsType = DeviceFire2SettingsType; //defaults to FIRE2 vnets with libicsneo - no firevnets! *pDeviceSettingsType = DeviceFire2SettingsType; //defaults to FIRE2 vnets with libicsneo - no firevnets!
break; break;
case NEODEVICE_VCAN3: case NEODEVICE_VCAN3_DEPRECATED:
*pDeviceSettingsType = DeviceVCAN3SettingsType; *pDeviceSettingsType = DeviceVCAN3SettingsTypeDeprecated;
break; break;
case NEODEVICE_FIRE: case NEODEVICE_FIRE_DEPRECATED:
*pDeviceSettingsType = DeviceFireSettingsType; *pDeviceSettingsType = DeviceFireSettingsType;
break; break;
case NEODEVICE_FIRE2: case NEODEVICE_FIRE2:
@@ -1061,17 +1061,17 @@ int LegacyDLLExport icsneoGetDeviceSettingsType(void* hObject, EPlasmaIonVnetCha
case NEODEVICE_VIVIDCAN: case NEODEVICE_VIVIDCAN:
*pDeviceSettingsType = DeviceVividCANSettingsType; *pDeviceSettingsType = DeviceVividCANSettingsType;
break; break;
case NEODEVICE_ECU_AVB: case NEODEVICE_ECU_AVB_DEPRECATED:
*pDeviceSettingsType = DeviceECU_AVBSettingsType; *pDeviceSettingsType = DeviceECU_AVBSettingsTypeDeprecated;
break; break;
case NEODEVICE_RADSUPERMOON: case NEODEVICE_RADSUPERMOON_DEPRECATED:
*pDeviceSettingsType = DeviceRADSuperMoonSettingsType; *pDeviceSettingsType = DeviceRADSuperMoonSettingsTypeDeprecated;
break; break;
case NEODEVICE_RADMOON2: case NEODEVICE_RADMOON2:
*pDeviceSettingsType = DeviceRADMoon2SettingsType; *pDeviceSettingsType = DeviceRADMoon2SettingsType;
break; break;
case NEODEVICE_RADGIGALOG: case NEODEVICE_RADGIGALOG_DEPRECATED:
*pDeviceSettingsType = DeviceRADGigalogSettingsType; *pDeviceSettingsType = DeviceRADGigalogSettingsTypeDeprecated;
break; break;
case NEODEVICE_RADMOON3: case NEODEVICE_RADMOON3:
*pDeviceSettingsType = DeviceRADMoon3SettingsType; *pDeviceSettingsType = DeviceRADMoon3SettingsType;
@@ -1088,6 +1088,8 @@ int LegacyDLLExport icsneoGetDeviceSettingsType(void* hObject, EPlasmaIonVnetCha
case NEODEVICE_FIRE3_FLEXRAY: case NEODEVICE_FIRE3_FLEXRAY:
*pDeviceSettingsType = DeviceFire3FlexraySettingsType; *pDeviceSettingsType = DeviceFire3FlexraySettingsType;
break; break;
case NEODEVICE_RAD_BMS:
*pDeviceSettingsType = DeviceRADBMSSettingsType;
default: default:
return 0; return 0;
} }
@@ -36,6 +36,7 @@ void init_devicetype(pybind11::module_& m) {
.value("RADEpsilon", DeviceType::Enum::RADEpsilon) .value("RADEpsilon", DeviceType::Enum::RADEpsilon)
.value("RADEpsilonXL", DeviceType::Enum::RADEpsilonXL) .value("RADEpsilonXL", DeviceType::Enum::RADEpsilonXL)
.value("RADGalaxy2", DeviceType::Enum::RADGalaxy2) .value("RADGalaxy2", DeviceType::Enum::RADGalaxy2)
.value("RADwBMS", DeviceType::Enum::RADwBMS)
.value("RADMoon3", DeviceType::Enum::RADMoon3) .value("RADMoon3", DeviceType::Enum::RADMoon3)
.value("RADGemini", DeviceType::Enum::RADGemini) .value("RADGemini", DeviceType::Enum::RADGemini)
.value("RADComet2", DeviceType::Enum::RADComet2) .value("RADComet2", DeviceType::Enum::RADComet2)
+1 -2
View File
@@ -1,7 +1,6 @@
#!/bin/sh #!/bin/sh
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Release -DLIBICSNEO_BUILD_EXAMPLES=ON \ cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Release -DLIBICSNEO_BUILD_EXAMPLES=ON -DLIBICSNEO_BUILD_UNIT_TESTS=ON -DLIBICSNEO_ENABLE_TCP=OFF || exit 1
-DLIBICSNEO_BUILD_UNIT_TESTS=ON -DLIBICSNEO_ENABLE_TCP=OFF || exit 1
cmake --build build || exit 1 cmake --build build || exit 1
+1 -2
View File
@@ -3,7 +3,6 @@
mkdir build >nul 2>&1 mkdir build >nul 2>&1
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Release -DLIBICSNEO_BUILD_UNIT_TESTS=ON ^ cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DLIBICSNEO_BUILD_UNIT_TESTS=ON-DLIBICSNEO_ENABLE_TCP=ON || exit /b 1
-DLIBICSNEO_ENABLE_TCP=ON || exit /b 1
cmake --build build || exit /b 1 cmake --build build || exit /b 1
+7
View File
@@ -26,6 +26,7 @@
#include "icsneo/communication/message/ethernetstatusmessage.h" #include "icsneo/communication/message/ethernetstatusmessage.h"
#include "icsneo/communication/message/networkmutexmessage.h" #include "icsneo/communication/message/networkmutexmessage.h"
#include "icsneo/communication/message/clientidmessage.h" #include "icsneo/communication/message/clientidmessage.h"
#include "icsneo/communication/message/spiportkeymessage.h"
#include "icsneo/communication/command.h" #include "icsneo/communication/command.h"
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
@@ -341,6 +342,9 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
case ExtendedCommand::LiveData: case ExtendedCommand::LiveData:
result = HardwareLiveDataPacket::DecodeToMessage(packet->data, report); result = HardwareLiveDataPacket::DecodeToMessage(packet->data, report);
return true; return true;
case ExtendedCommand::ExecuteSPIPortKeyOperation:
result = SPIPortKeyMessage::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::GetTC10Status: case ExtendedCommand::GetTC10Status:
result = TC10StatusMessage::DecodeToMessage(packet->data); result = TC10StatusMessage::DecodeToMessage(packet->data);
return true; return true;
@@ -563,6 +567,9 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
} }
break; break;
} }
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
} }
// For the moment other types of messages will automatically be decoded as raw messages // For the moment other types of messages will automatically be decoded as raw messages
+3 -1
View File
@@ -234,7 +234,9 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
result = packetizer.packetWrap(result, false); result = packetizer.packetWrap(result, false);
return true; return true;
} }
break; default:
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed Message
} }
// Early returns may mean we don't reach this far, check the type you're concerned with // Early returns may mean we don't reach this far, check the type you're concerned with
+2
View File
@@ -163,6 +163,8 @@ void A2BMessage::setChannelSample(Direction dir, uint8_t channel, size_t frame,
case PCMType::L24: case PCMType::L24:
sampleToSet = sampleToSet << 8; sampleToSet = sampleToSet << 8;
break; break;
case PCMType::L32:
break;
} }
if(channelSize16) { if(channelSize16) {
+1 -1
View File
@@ -35,7 +35,7 @@ bool EthPhyMessage::appendPhyMessage(bool writeEnable, bool clause45, uint8_t ph
bool EthPhyMessage::appendPhyMessage(std::shared_ptr<PhyMessage> message) bool EthPhyMessage::appendPhyMessage(std::shared_ptr<PhyMessage> message)
{ {
if(message != nullptr) if(message)
{ {
messages.push_back(message); messages.push_back(message);
return true; return true;
@@ -0,0 +1,27 @@
#include "icsneo/communication/message/spiportkeymessage.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/communication/command.h"
#include "icsneo/communication/network.h"
using namespace icsneo;
std::shared_ptr<SPIPortKeyMessage> SPIPortKeyMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(ExtendedResponseMessage::ResponseHeader))
return nullptr;
const auto* hdr = reinterpret_cast<const ExtendedResponseMessage::ResponseHeader*>(bytestream.data());
if(hdr->command != ExtendedCommand::ExecuteSPIPortKeyOperation)
return nullptr;
const size_t required = sizeof(ExtendedResponseMessage::ResponseHeader) + sizeof(SPIPortKeyPacket);
if(bytestream.size() < required)
return nullptr;
auto msg = std::make_shared<SPIPortKeyMessage>();
const auto* packet = reinterpret_cast<const SPIPortKeyPacket*>(bytestream.data() + sizeof(ExtendedResponseMessage::ResponseHeader));
msg->isKeyLoaded = packet->isKeyLoaded;
return msg;
}
@@ -142,6 +142,8 @@ void MultiChannelCommunication::hidReadTask() {
dispatchMessage(msg); dispatchMessage(msg);
break; break;
} }
default:
break;
} }
if(currentQueue == nullptr) { if(currentQueue == nullptr) {
+54 -114
View File
@@ -92,10 +92,6 @@ Device::~Device() {
disableMessagePolling(); disableMessagePolling();
if(isOpen()) if(isOpen())
close(); close();
if(heartbeatThread.joinable()) {
stopHeartbeatThread = true;
heartbeatThread.join();
}
} }
uint16_t Device::getTimestampResolution() const { uint16_t Device::getTimestampResolution() const {
@@ -288,6 +284,8 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
return false; return false;
} }
startHeartbeat();
APIEvent::Type attemptErr = attemptToBeginCommunication(); APIEvent::Type attemptErr = attemptToBeginCommunication();
if(attemptErr != APIEvent::Type::NoErrorFound) { if(attemptErr != APIEvent::Type::NoErrorFound) {
// We could not communicate with the device, let's see if an extension can // We could not communicate with the device, let's see if an extension can
@@ -334,79 +332,6 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
EventManager::GetInstance().cancelErrorDowngradingOnCurrentThread(); EventManager::GetInstance().cancelErrorDowngradingOnCurrentThread();
} }
MessageFilter filter;
filter.includeInternalInAny = true;
internalHandlerCallbackID = com->addMessageCallback(std::make_shared<MessageCallback>(filter, [this](std::shared_ptr<Message> message) {
handleInternalMessage(message);
}));
// Clear the previous heartbeat thread, in case open() was called on this instance more than once
if(heartbeatThread.joinable())
heartbeatThread.join();
stopHeartbeatThread = false;
heartbeatThread = std::thread([this]() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
MessageFilter filter;
filter.includeInternalInAny = true;
std::condition_variable heartbeatCV;
std::mutex receivedMessageMutex;
bool receivedMessage = false;
auto messageReceivedCallbackID = com->addMessageCallback(std::make_shared<MessageCallback>(filter, [&](std::shared_ptr<Message>) {
{
std::scoped_lock<std::mutex> lk(receivedMessageMutex);
receivedMessage = true;
}
heartbeatCV.notify_all();
}));
// Give the device time to get situated
auto i = 150;
while(!stopHeartbeatThread && i != 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
i--;
}
while(!stopHeartbeatThread) {
std::unique_lock<std::mutex> recvLk(receivedMessageMutex);
// Wait for 110ms for a possible heartbeat
if(heartbeatCV.wait_for(recvLk, std::chrono::milliseconds(110), [&]() { return receivedMessage; })) {
receivedMessage = false;
} else if(!stopHeartbeatThread) { // Add this condition here in case the thread was stopped while waiting for the last message
// Some communication, such as the bootloader and extractor interfaces, must
// redirect the input stream from the device as it will no longer be in the
// packet format we expect here. As a result, status updates will not reach
// us here and suppressDisconnects() must be used. We don't want to request
// a status and then redirect the stream, as we'll then be polluting an
// otherwise quiet stream. This lock makes sure suppressDisconnects() will
// block until we've either gotten our status update or disconnected from
// the device.
std::unique_lock<std::mutex> lk(heartbeatMutex);
if(heartbeatSuppressed()) continue;
// No heartbeat received, request a status
com->sendCommand(Command::RequestStatusUpdate);
// Check if we got a message, and if not, if settings are being applied
if(heartbeatCV.wait_for(recvLk, std::chrono::milliseconds(3500), [&](){ return receivedMessage; })) {
receivedMessage = false;
} else {
if(!stopHeartbeatThread) {
close();
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
}
break;
}
}
}
com->removeMessageCallback(messageReceivedCallbackID);
});
if(supportsLiveData()) if(supportsLiveData())
clearAllLiveData(); clearAllLiveData();
@@ -503,7 +428,7 @@ bool Device::close() {
return false; return false;
} }
stopHeartbeatThread = true; stopHeartbeat();
if (isMessagePollingEnabled()) { if (isMessagePollingEnabled()) {
disableMessagePolling(); disableMessagePolling();
@@ -534,31 +459,15 @@ bool Device::goOnline() {
if(!enableNetworkCommunication(true, onlineTimeoutMs)) if(!enableNetworkCommunication(true, onlineTimeoutMs))
return false; return false;
auto startTime = std::chrono::system_clock::now();
ledState = LEDState::Online; ledState = LEDState::Online;
updateLEDState(); updateLEDState();
std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::Reset_Status); // (re)start the keeponline
filter->includeInternalInAny = true; keeponline = std::make_unique<Periodic>([this] {
static std::vector<uint8_t> timeoutBytes = std::vector<uint8_t>((uint8_t*)&onlineTimeoutMs, (uint8_t*)&onlineTimeoutMs + sizeof(onlineTimeoutMs));
// Wait until communication is enabled or 5 seconds, whichever comes first return com->sendCommand(Command::KeepAlive, timeoutBytes);
while((std::chrono::system_clock::now() - startTime) < std::chrono::seconds(5)) { }, std::chrono::milliseconds(onlineTimeoutMs / 4));
if(latestResetStatus && latestResetStatus->comEnabled)
break;
bool failOut = false;
com->waitForMessageSync([this, &failOut]() {
if(!com->sendCommand(Command::RequestStatusUpdate)) {
failOut = true;
return false;
}
return true;
}, filter, std::chrono::milliseconds(100));
if(failOut)
return false;
}
if(supportsNetworkMutex) { if(supportsNetworkMutex) {
assignedClientId = com->getClientIDSync(); assignedClientId = com->getClientIDSync();
@@ -575,41 +484,46 @@ bool Device::goOnline() {
case NetworkMutexEvent::Acquired: case NetworkMutexEvent::Acquired:
lockedNetworks.emplace(*netMutexMsg->networks.begin()); lockedNetworks.emplace(*netMutexMsg->networks.begin());
break; break;
case NetworkMutexEvent::Expired:
case NetworkMutexEvent::Preempted:
case NetworkMutexEvent::Released: { case NetworkMutexEvent::Released: {
auto it = lockedNetworks.find(*netMutexMsg->networks.begin()); auto it = lockedNetworks.find(*netMutexMsg->networks.begin());
if (it != lockedNetworks.end()) if (it != lockedNetworks.end())
lockedNetworks.erase(it); lockedNetworks.erase(it);
break; break;
} }
case NetworkMutexEvent::Queued:
break;
} }
} }
}); });
} }
} }
// (re)start the keeponline
keeponline = std::make_unique<Periodic>([this] {
static std::vector<uint8_t> timeoutBytes = std::vector<uint8_t>((uint8_t*)&onlineTimeoutMs, (uint8_t*)&onlineTimeoutMs + sizeof(onlineTimeoutMs));
return com->sendCommand(Command::KeepAlive, timeoutBytes);
}, std::chrono::milliseconds(onlineTimeoutMs / 4));
online = true; online = true;
// restart the heartbeat in online mode
restartHeartbeat();
forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOnline(); return true; }); forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOnline(); return true; });
return true; return true;
} }
bool Device::goOffline() { bool Device::goOffline() {
online = false;
keeponline.reset(); keeponline.reset();
// restart the heartbeat in offline mode
restartHeartbeat();
if(networkMutexCallbackHandle) if(networkMutexCallbackHandle)
removeMessageCallback(*networkMutexCallbackHandle); removeMessageCallback(*networkMutexCallbackHandle);
forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOffline(); return true; }); forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOffline(); return true; });
if(isDisconnected()) { if(isDisconnected()) {
online = false;
return true; return true;
} }
@@ -625,8 +539,6 @@ bool Device::goOffline() {
updateLEDState(); updateLEDState();
online = false;
return true; return true;
} }
@@ -1988,11 +1900,9 @@ void Device::stopScriptStatusThreadIfNecessary(std::unique_lock<std::mutex> lk)
} }
Lifetime Device::suppressDisconnects() { Lifetime Device::suppressDisconnects() {
std::lock_guard<std::mutex> lk(heartbeatMutex); stopHeartbeat();
heartbeatSuppressedByUser++;
return Lifetime([this] { return Lifetime([this] {
std::lock_guard<std::mutex> lk2(heartbeatMutex); startHeartbeat();
heartbeatSuppressedByUser--;
}); });
} }
@@ -2128,6 +2038,18 @@ std::optional<EthPhyMessage> Device::sendEthPhyMsg(const EthPhyMessage& message,
return std::make_optional<EthPhyMessage>(*retMsg); return std::make_optional<EthPhyMessage>(*retMsg);
} }
bool Device::sendSPIPortKeyOperation(uint8_t portIndex, SPIPortKeyMessage::Operation op, std::array<uint8_t, 16> key) {
std::vector<uint8_t> args(sizeof(SPIPortKeyMessage::SPIPortKeyPacket));
auto& params = *reinterpret_cast<SPIPortKeyMessage::SPIPortKeyPacket*>(args.data());
params.op = op;
params.portIndex = portIndex;
std::copy(key.begin(), key.end(), params.key);
if(!com->sendCommand(ExtendedCommand::ExecuteSPIPortKeyOperation, args)) {
return false;
}
return true;
}
std::optional<bool> Device::SetRootDirectoryEntryFlags(uint8_t mask, uint8_t values, uint32_t collectionEntryByteAddress) std::optional<bool> Device::SetRootDirectoryEntryFlags(uint8_t mask, uint8_t values, uint32_t collectionEntryByteAddress)
{ {
if(!supportsWiVI()) if(!supportsWiVI())
@@ -3297,11 +3219,12 @@ bool Device::findVSAOffsetFromTimepoint(ICSClock::time_point point, uint64_t& vs
std::shared_ptr<VSA> midRecord; std::shared_ptr<VSA> midRecord;
auto midRecordStatus = parser.getRecordFromBytes(buffer.data(), Disk::SectorSize, midRecord); auto midRecordStatus = parser.getRecordFromBytes(buffer.data(), Disk::SectorSize, midRecord);
switch(midRecordStatus) { switch(midRecordStatus) {
case VSAParser::RecordParseStatus::NotARecordStart: case VSAParser::RecordParseStatus::NotARecordStart: {
// This part of the buffer does not contain records // This part of the buffer does not contain records
rightIndex = midIndex - 1; rightIndex = midIndex - 1;
continue; continue;
case VSAParser::RecordParseStatus::ConsecutiveExtended: }
case VSAParser::RecordParseStatus::ConsecutiveExtended: {
// We dropped in the middle of an extended message record // We dropped in the middle of an extended message record
auto extendedRecord = std::dynamic_pointer_cast<VSAExtendedMessage>(midRecord); auto extendedRecord = std::dynamic_pointer_cast<VSAExtendedMessage>(midRecord);
uint64_t pos = readPos; uint64_t pos = readPos;
@@ -3316,6 +3239,9 @@ bool Device::findVSAOffsetFromTimepoint(ICSClock::time_point point, uint64_t& vs
midIndex = (pos - firstOffset) / Disk::SectorSize; midIndex = (pos - firstOffset) / Disk::SectorSize;
midRecord = extendedRecord; midRecord = extendedRecord;
break; break;
}
default:
break;
} }
if(midIndex <= leftIndex) { if(midIndex <= leftIndex) {
// Extended records cause problems with binary search // Extended records cause problems with binary search
@@ -4156,3 +4082,17 @@ bool Device::unlockAllNetworks()
return true; return true;
} }
void Device::startHeartbeat() {
if(!heartbeat)
heartbeat = std::make_unique<Heartbeat>(*this);
}
void Device::stopHeartbeat() {
heartbeat.reset();
}
void Device::restartHeartbeat() {
stopHeartbeat();
startHeartbeat();
}
+8
View File
@@ -241,6 +241,10 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
makeIfSerialMatches<RADSupermoon>(dev, newFoundDevices); makeIfSerialMatches<RADSupermoon>(dev, newFoundDevices);
#endif #endif
#ifdef __RADWBMS_H_
makeIfSerialMatches<RADwBMS>(dev, newFoundDevices);
#endif
#ifdef __VALUECAN3_H_ #ifdef __VALUECAN3_H_
makeIfSerialRangeMatches<ValueCAN3>(dev, newFoundDevices); makeIfSerialRangeMatches<ValueCAN3>(dev, newFoundDevices);
#endif #endif
@@ -404,6 +408,10 @@ const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
RADSupermoon::DEVICE_TYPE, RADSupermoon::DEVICE_TYPE,
#endif #endif
#ifdef __RADWBMS_H_
RADwBMS::DEVICE_TYPE,
#endif
#ifdef __VALUECAN3_H_ #ifdef __VALUECAN3_H_
ValueCAN3::DEVICE_TYPE, ValueCAN3::DEVICE_TYPE,
#endif #endif
+24 -17
View File
@@ -1,9 +1,16 @@
#include "icsneo/device/device.h"
#include "icsneo/device/idevicesettings.h" #include "icsneo/device/idevicesettings.h"
#include "icsneo/communication/message/filter/main51messagefilter.h" #include "icsneo/communication/message/filter/main51messagefilter.h"
#include <cstring> #include <cstring>
using namespace icsneo; using namespace icsneo;
IDeviceSettings::IDeviceSettings(Device* device, size_t size)
: device(device), report(device->report), structSize(size) {}
IDeviceSettings::IDeviceSettings(warn_t createInoperableSettings, Device* device)
: disabled(true), readonly(true), report(device->report), structSize(0) { (void)createInoperableSettings; }
std::optional<uint16_t> IDeviceSettings::CalculateGSChecksum(const std::vector<uint8_t>& settings) { std::optional<uint16_t> IDeviceSettings::CalculateGSChecksum(const std::vector<uint8_t>& settings) {
const uint16_t* p = reinterpret_cast<const uint16_t*>(settings.data()); const uint16_t* p = reinterpret_cast<const uint16_t*>(settings.data());
size_t words = settings.size(); size_t words = settings.size();
@@ -166,7 +173,7 @@ bool IDeviceSettings::refresh() {
} }
std::vector<uint8_t> rxSettings; std::vector<uint8_t> rxSettings;
bool ret = com->getSettingsSync(rxSettings); bool ret = device->com->getSettingsSync(rxSettings);
if(!ret) { if(!ret) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error); report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false; return false;
@@ -231,10 +238,10 @@ bool IDeviceSettings::apply(bool temporary) {
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size()); memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
// Pause I/O with the device while the settings are applied // Pause I/O with the device while the settings are applied
applyingSettings = true; device->stopHeartbeat();
std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() { std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(device->com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return device->com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000))); }, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) { // We did not receive a response if(!msg || msg->data[0] != 1) { // We did not receive a response
@@ -259,8 +266,8 @@ bool IDeviceSettings::apply(bool temporary) {
bytestream[6] = (uint8_t)(*gsChecksum >> 8); bytestream[6] = (uint8_t)(*gsChecksum >> 8);
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size()); memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() { msg = std::dynamic_pointer_cast<Main51Message>(device->com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return device->com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000))); }, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
@@ -272,12 +279,12 @@ bool IDeviceSettings::apply(bool temporary) {
} }
if(!temporary) { if(!temporary) {
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() { msg = std::dynamic_pointer_cast<Main51Message>(device->com->waitForMessageSync([this]() {
return com->sendCommand(Command::SaveSettings); return device->com->sendCommand(Command::SaveSettings);
}, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000))); }, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000)));
} }
applyingSettings = false; device->startHeartbeat();
refresh(); // Refresh our buffer with what the device has, whether we were successful or not refresh(); // Refresh our buffer with what the device has, whether we were successful or not
@@ -299,10 +306,10 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
return false; return false;
} }
applyingSettings = true; device->stopHeartbeat();
std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() { std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(device->com->waitForMessageSync([this]() {
return com->sendCommand(Command::SetDefaultSettings); return device->com->sendCommand(Command::SetDefaultSettings);
}, std::make_shared<Main51MessageFilter>(Command::SetDefaultSettings), std::chrono::milliseconds(5000))); }, std::make_shared<Main51MessageFilter>(Command::SetDefaultSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
@@ -336,8 +343,8 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
bytestream[6] = (uint8_t)(*gsChecksum >> 8); bytestream[6] = (uint8_t)(*gsChecksum >> 8);
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size()); memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() { msg = std::dynamic_pointer_cast<Main51Message>(device->com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return device->com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000))); }, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
@@ -349,12 +356,12 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
} }
if(!temporary) { if(!temporary) {
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() { msg = std::dynamic_pointer_cast<Main51Message>(device->com->waitForMessageSync([this]() {
return com->sendCommand(Command::SaveSettings); return device->com->sendCommand(Command::SaveSettings);
}, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000))); }, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000)));
} }
applyingSettings = false; device->startHeartbeat();
refresh(); // Refresh our buffer with what the device has, whether we were successful or not refresh(); // Refresh our buffer with what the device has, whether we were successful or not
+8
View File
@@ -114,3 +114,11 @@ PerfTest
.. literalinclude:: ../../examples/c2/perf_test/src/main.c .. literalinclude:: ../../examples/c2/perf_test/src/main.c
:language: c :language: c
Termination Groups
==================
:download:`Download example <../../examples/c2/termination/src/main.c>`
.. literalinclude:: ../../examples/c2/termination/src/main.c
:language: c
+5
View File
@@ -8,6 +8,7 @@ option(LIBICSNEO_BUILD_C2_DISKFORMAT_EXAMPLE "Build the C2 disk format example."
option(LIBICSNEO_BUILD_C2_RECONNECT_EXAMPLE "Build the C2 reconnect example." ON) option(LIBICSNEO_BUILD_C2_RECONNECT_EXAMPLE "Build the C2 reconnect example." ON)
option(LIBICSNEO_BUILD_C2_DEVICE_INFO_EXAMPLE "Build the C2 device info example." ON) option(LIBICSNEO_BUILD_C2_DEVICE_INFO_EXAMPLE "Build the C2 device info example." ON)
option(LIBICSNEO_BUILD_C2_CHIP_VERSIONS_EXAMPLE "Build the C2 chip versions example." ON) option(LIBICSNEO_BUILD_C2_CHIP_VERSIONS_EXAMPLE "Build the C2 chip versions example." ON)
option(LIBICSNEO_BUILD_C2_TERMINATION_EXAMPLE "Build the C2 termination groups example." ON)
option(LIBICSNEO_BUILD_C2_LIN_EXAMPLE "Build the C2 LIN example." ON) option(LIBICSNEO_BUILD_C2_LIN_EXAMPLE "Build the C2 LIN example." ON)
option(LIBICSNEO_BUILD_C2_LIN_TRANSMIT_EXAMPLE "Build the C2 LIN transmit example." ON) option(LIBICSNEO_BUILD_C2_LIN_TRANSMIT_EXAMPLE "Build the C2 LIN transmit example." ON)
option(LIBICSNEO_BUILD_C2_ETHERNET_TRANSMIT_EXAMPLE "Build the C2 ethernet transmit example." ON) option(LIBICSNEO_BUILD_C2_ETHERNET_TRANSMIT_EXAMPLE "Build the C2 ethernet transmit example." ON)
@@ -78,6 +79,10 @@ if(LIBICSNEO_BUILD_C2_CHIP_VERSIONS_EXAMPLE)
add_subdirectory(c2/chip_versions) add_subdirectory(c2/chip_versions)
endif() endif()
if(LIBICSNEO_BUILD_C2_TERMINATION_EXAMPLE)
add_subdirectory(c2/termination)
endif()
if(LIBICSNEO_BUILD_C2_LIN_EXAMPLE) if(LIBICSNEO_BUILD_C2_LIN_EXAMPLE)
add_subdirectory(c2/lin) add_subdirectory(c2/lin)
endif() endif()
+5 -5
View File
@@ -58,7 +58,7 @@ int main() {
msg1.Protocol = SPY_PROTOCOL_LIN; msg1.Protocol = SPY_PROTOCOL_LIN;
msg1.StatusBitField = 0; msg1.StatusBitField = 0;
msg1.StatusBitField2 = 0; msg1.StatusBitField2 = 0;
lNetworkID = NETID_LIN_02; lNetworkID = NETID_LIN2;
msg1.Header[0] = 0x11; //protected ID msg1.Header[0] = 0x11; //protected ID
msg1.Header[1] = 0xaa; msg1.Header[1] = 0xaa;
msg1.Header[2] = 0xbb; msg1.Header[2] = 0xbb;
@@ -80,7 +80,7 @@ int main() {
icsSpyMessageJ1850 msg2 = {0}; icsSpyMessageJ1850 msg2 = {0};
msg2.Protocol = SPY_PROTOCOL_LIN; msg2.Protocol = SPY_PROTOCOL_LIN;
msg2.StatusBitField = SPY_STATUS_INIT_MESSAGE; msg2.StatusBitField = SPY_STATUS_INIT_MESSAGE;
lNetworkID = NETID_LIN_01; lNetworkID = NETID_LIN;
msg2.Header[0] = 0x11; //protected ID msg2.Header[0] = 0x11; //protected ID
msg2.NumberBytesData = 0; msg2.NumberBytesData = 0;
msg2.NumberBytesHeader = 1; msg2.NumberBytesHeader = 1;
@@ -96,7 +96,7 @@ int main() {
msg3.Protocol = SPY_PROTOCOL_LIN; msg3.Protocol = SPY_PROTOCOL_LIN;
msg3.StatusBitField = SPY_STATUS_INIT_MESSAGE; msg3.StatusBitField = SPY_STATUS_INIT_MESSAGE;
msg3.StatusBitField2 = 0; msg3.StatusBitField2 = 0;
lNetworkID = NETID_LIN_01; lNetworkID = NETID_LIN;
msg3.Header[0] = 0xe2; //protected ID msg3.Header[0] = 0xe2; //protected ID
msg3.Header[1] = 0x44; msg3.Header[1] = 0x44;
msg3.Header[2] = 0x33; msg3.Header[2] = 0x33;
@@ -131,10 +131,10 @@ int main() {
const icsSpyMessageJ1850* linMsg = (icsSpyMessageJ1850*)&rxMsg[idx]; const icsSpyMessageJ1850* linMsg = (icsSpyMessageJ1850*)&rxMsg[idx];
size_t frameLen = (linMsg->NumberBytesHeader + linMsg->NumberBytesData); size_t frameLen = (linMsg->NumberBytesHeader + linMsg->NumberBytesData);
size_t dataLen = (frameLen > 2) ? (frameLen - 2) : 0; size_t dataLen = (frameLen > 2) ? (frameLen - 2) : 0;
if(linMsg->NetworkID == NETID_LIN_01) { if(linMsg->NetworkID == NETID_LIN) {
printf("LIN 1 | ID: 0x%02x [%zu] ", linMsg->Header[0], dataLen); printf("LIN 1 | ID: 0x%02x [%zu] ", linMsg->Header[0], dataLen);
} }
else if (linMsg->NetworkID == NETID_LIN_02) { else if (linMsg->NetworkID == NETID_LIN2) {
printf("LIN 2 | ID: 0x%02x [%zu] ", linMsg->Header[0], dataLen); printf("LIN 2 | ID: 0x%02x [%zu] ", linMsg->Header[0], dataLen);
} }
+1 -1
View File
@@ -112,7 +112,7 @@ int main() {
} }
printf("MACs: %u entr%s\n", mac_count, mac_count == 1 ? "y" : "ies"); printf("MACs: %u entr%s\n", mac_count, mac_count == 1 ? "y" : "ies");
for(icsneoc2_mac_addr_entry_t* cur = macs; cur; cur = icsneoc2_mac_addresses_next(cur)) { for(icsneoc2_mac_addr_entry_t* cur = macs; cur; cur = icsneoc2_mac_addresses_next(cur)) {
_icsneoc2_netid_t network_id; icsneoc2_netid_t network_id;
icsneoc2_mac_network_id_get(cur, &network_id); icsneoc2_mac_network_id_get(cur, &network_id);
printf(" Network %-5u ", (unsigned)network_id); printf(" Network %-5u ", (unsigned)network_id);
uint8_t address[6]; uint8_t address[6];
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-termination-example src/main.c)
target_link_libraries(libicsneoc2-termination-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-termination-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+91
View File
@@ -0,0 +1,91 @@
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <icsneo/icsneoc2settings.h>
#include <stdio.h>
#include <stdlib.h>
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[64];
size_t error_str_len = sizeof(error_str);
icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_str_len);
if(res != icsneoc2_error_success) {
printf("%s: Failed to get string for error code %u with error code %u\n", message, error, res);
return (int)res;
}
printf("%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
int main() {
icsneoc2_error_t res;
icsneoc2_device_t* device = NULL;
res = icsneoc2_device_open_first(0, icsneoc2_open_options_default, &device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to open first device", res);
}
char description[128] = {0};
size_t description_length = sizeof(description);
icsneoc2_device_description_get(device, description, &description_length);
printf("Opened device: %s\n\n", description);
size_t count = 0;
icsneoc2_termination_group_t* groups = NULL;
res = icsneoc2_settings_termination_groups_enumerate(device, &groups, &count);
if(res != icsneoc2_error_success) {
print_error_code("Failed to enumerate termination groups", res);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 1;
}
if(count == 0) {
printf("This device does not support software switchable termination.\n");
} else {
printf("Found %zu termination group(s) (only one network per group may be terminated at a time):\n", count);
}
size_t group_index = 0;
for(icsneoc2_termination_group_t* group = groups; group; group = icsneoc2_termination_group_next(group), group_index++) {
// First call with a NULL buffer to learn how many networks are in this group.
size_t network_count = 0;
icsneoc2_termination_group_networks_get(group, NULL, &network_count);
icsneoc2_netid_t* netids = (icsneoc2_netid_t*)malloc(network_count * sizeof(icsneoc2_netid_t));
if(!netids) {
print_error_code("Out of memory", icsneoc2_error_out_of_memory);
break;
}
// Second call to fill the buffer.
res = icsneoc2_termination_group_networks_get(group, netids, &network_count);
if(res != icsneoc2_error_success) {
print_error_code("Failed to get termination group networks", res);
free(netids);
continue;
}
printf(" Group %zu:", group_index);
for(size_t i = 0; i < network_count; i++) {
char name[64] = {0};
size_t name_length = sizeof(name);
if(icsneoc2_netid_name_get(netids[i], name, &name_length) == icsneoc2_error_success) {
printf(" %s", name);
} else {
printf(" %u", netids[i]);
}
if(i + 1 < network_count) {
printf(",");
}
}
printf("\n");
free(netids);
}
icsneoc2_settings_termination_groups_free(groups);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 0;
}
+38
View File
@@ -0,0 +1,38 @@
#ifndef __HEARTBEAT_H__
#define __HEARTBEAT_H__
#ifdef __cplusplus
#include <thread>
#include <condition_variable>
#include <mutex>
namespace icsneo {
class Device;
class Heartbeat {
public:
Heartbeat(Device& device);
~Heartbeat();
private:
enum class Mode {
Passive, // ResetStatus messages arrive without requesting
Active, // RequestStatusUpdate needs to be sent
};
Device& device;
const Mode mode;
bool stop = false;
std::mutex mutex;
std::condition_variable cv;
std::thread thread;
void run();
};
} // icsneo
#endif // __cplusplus
#endif // __HEARTBEAT_H__
+249
View File
@@ -0,0 +1,249 @@
// --------------------------------------------------------------------------
// COPYRIGHT INTREPID CONTROL SYSTEMS, INC. (c) 1994-20xx
// Confidential and proprietary. This document and its contents are the
// property of Intrepid Control Systems, Inc. It is not to be copied,
// distributed, or otherwise disclosed or used without the prior written
// consent of Intrepid Control Systems Inc.
// All rights reserved.
// --------------------------------------------------------------------------
// SPY Status Bit Definitions
// Generated automatically - DO NOT MODIFY
// Modify cicsSpyStatusBits_config.yml and run cicsSpyStatusBits_gen.py
// Generated on: 2025-07-14 14:31:40
#ifndef CICSSPYSTATUSBITS_H_
#define CICSSPYSTATUSBITS_H_ 1
// WARNING: The following bit conflicts were detected:
// spystatus value 0x10000000: // VSI value 'SPY_STATUS_VSI_IFR_CRC_BIT' conflicts with common value 'SPY_STATUS_PDU'
// spystatus value 0x10000000: // A2B value 'SPY_STATUS_A2B_CONTROL' conflicts with common value 'SPY_STATUS_PDU'
// spystatus value 0x08: // A2B value 'SPY_STATUS_A2B_SCF_VALID_WAITING' conflicts with common value 'SPY_STATUS_REMOTE_FRAME'
// spystatus value 0x40000000: // A2B value 'SPY_STATUS_A2B_UPSTREAM' conflicts with common value 'SPY_STATUS_HIGH_SPEED'
// spystatus value 0x10000000: // FLEXRAY value 'SPY_STATUS_FLEXRAY_PDU' conflicts with common value 'SPY_STATUS_PDU'
// spystatus value 0x40000000: // FLEXRAY value 'SPY_STATUS_FLEXRAY_PDU_UPDATE_BIT_SET' conflicts with common value 'SPY_STATUS_HIGH_SPEED'
// spystatus value 0x08: // FLEXRAY value 'SPY_STATUS_FLEXRAY_PDU_NO_UPDATE_BIT' conflicts with common value 'SPY_STATUS_REMOTE_FRAME'
// Glyph definitions
// '|' - byte divider
// '.' - nibble divider
// '-' - unused bit
// 'o' - common bit
// 'x' - protocol specific bit
// '!' - conflict bit
// SPYSTATUS bit definitions
// SPYSTATUS - Common bits
// |oo-o.oooo|oooo.oooo|oooo.oo-o|oo-o.oooo|
#define SPY_STATUS_GLOBAL_ERR 0x01 // Global error flag
#define SPY_STATUS_TX_MSG 0x02 // Transmitted message
#define SPY_STATUS_XTD_FRAME 0x04 // Extended frame
#define SPY_STATUS_REMOTE_FRAME 0x08 // Remote frame
#define SPY_STATUS_CRC_ERROR 0x10 // CRC error
#define SPY_STATUS_INCOMPLETE_FRAME 0x40 // Incomplete frame
#define SPY_STATUS_LOST_ARBITRATION 0x80 // Lost arbitration
#define SPY_STATUS_UNDEFINED_ERROR 0x0100 // Undefined error
#define SPY_STATUS_BUS_RECOVERED 0x0400 // Bus recovered
#define SPY_STATUS_BUS_SHORTED_PLUS 0x0800 // Bus shorted to plus
#define SPY_STATUS_BUS_SHORTED_GND 0x1000 // Bus shorted to ground
#define SPY_STATUS_CHECKSUM_ERROR 0x2000 // Checksum error
#define SPY_STATUS_BAD_MESSAGE_BIT_TIME_ERROR 0x4000 // Bad message bit time error
#define SPY_STATUS_TX_NOMATCH 0x8000 // TX no match
#define SPY_STATUS_COMM_IN_OVERFLOW 0x010000 // Communication input overflow
#define SPY_STATUS_EXPECTED_LEN_MISMATCH 0x020000 // Expected length mismatch
#define SPY_STATUS_MSG_NO_MATCH 0x040000 // Message no match
#define SPY_STATUS_BREAK 0x080000 // Break detected
#define SPY_STATUS_AVSI_REC_OVERFLOW 0x100000 // AVSI record overflow
#define SPY_STATUS_TEST_TRIGGER 0x200000 // Test trigger
#define SPY_STATUS_AUDIO_COMMENT 0x400000 // Audio comment
#define SPY_STATUS_GPS_DATA 0x800000 // GPS data
#define SPY_STATUS_ANALOG_DIGITAL_INPUT 0x01000000 // Analog digital input
#define SPY_STATUS_TEXT_COMMENT 0x02000000 // Text comment
#define SPY_STATUS_NETWORK_MESSAGE_TYPE 0x04000000 // Network message type
#define SPY_STATUS_VSI_TX_UNDERRUN 0x08000000 // VSI TX underrun
#define SPY_STATUS_PDU 0x10000000 // PDU message
#define SPY_STATUS_HIGH_SPEED 0x40000000 // High speed
#define SPY_STATUS_EXTENDED 0x80000000 // Extended - if this bit is set than decode StatusBitField3 in AckBytes
// SPYSTATUS - A2B protocol bits
// |o!x!.oooo|oooo.oooo|oooo.oo-o|oo-o.!ooo|
#define SPY_STATUS_A2B_SCF_VALID_WAITING 0x08 // A2B SCF valid waiting
#define SPY_STATUS_A2B_CONTROL 0x10000000 // A2B control message
#define SPY_STATUS_A2B_MONITOR 0x20000000 // A2B monitor message
#define SPY_STATUS_A2B_UPSTREAM 0x40000000 // A2B upstream message
// SPYSTATUS - CAN protocol bits
// |ooxo.oooo|oooo.oooo|oooo.ooxo|ooxo.oooo|
#define SPY_STATUS_CAN_ERROR_PASSIVE 0x20 // CAN error passive state
#define SPY_STATUS_CAN_BUS_OFF 0x0200 // CAN bus off state
#define SPY_STATUS_CANFD 0x20000000 // CAN FD frame
// SPYSTATUS - ETHERNET protocol bits
// |oo-o.oooo|oooo.oooo|oooo.oo-o|ooxo.oooo|
#define SPY_STATUS_HEADERCRC_ERROR 0x20 // Header CRC error
// SPYSTATUS - FLEXRAY protocol bits
// |o!-!.oooo|oooo.oooo|oooo.oo-o|oo-o.!ooo|
#define SPY_STATUS_FLEXRAY_PDU_NO_UPDATE_BIT 0x08 // FlexRay PDU no update bit
#define SPY_STATUS_FLEXRAY_PDU 0x10000000 // FlexRay PDU (alias for SPY_STATUS_PDU)
#define SPY_STATUS_FLEXRAY_PDU_UPDATE_BIT_SET 0x40000000 // FlexRay PDU update bit set
// SPYSTATUS - LIN protocol bits
// |ooxo.oooo|oooo.oooo|oooo.oo-o|oo-o.oooo|
#define SPY_STATUS_LIN_MASTER 0x20000000 // LIN master message
// SPYSTATUS - VSI protocol bits
// |oox!.oooo|oooo.oooo|oooo.oo-o|oo-o.oooo|
#define SPY_STATUS_VSI_IFR_CRC_BIT 0x10000000 // VSI IFR CRC bit
#define SPY_STATUS_INIT_MESSAGE 0x20000000 // Initialization message
// SPYSTATUS2 bit definitions
// SPYSTATUS2 - Common bits
// |----.----|---o.--oo|----.----|----.oooo|
#define SPY_STATUS2_HAS_VALUE 0x01
#define SPY_STATUS2_VALUE_IS_BOOLEAN 0x02
#define SPY_STATUS2_HIGH_VOLTAGE 0x04
#define SPY_STATUS2_LONG_MESSAGE 0x08
#define SPY_STATUS2_GLOBAL_CHANGE 0x010000
#define SPY_STATUS2_ERROR_FRAME 0x020000
#define SPY_STATUS2_END_OF_LONG_MESSAGE 0x100000
// SPYSTATUS2 - CAN protocol bits
// |----.----|-xxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_CAN_ISO15765_LOGICAL_FRAME 0x200000
#define SPY_STATUS2_CAN_HAVE_LINK_DATA 0x400000
// SPYSTATUS2 - ETHERNET protocol bits
// |xxxx.xxxx|xxxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_ETHERNET_CRC_ERROR 0x200000
#define SPY_STATUS2_ETHERNET_FRAME_TOO_SHORT 0x400000
#define SPY_STATUS2_ETHERNET_FCS_AVAILABLE 0x800000 // This frame contains FCS (4 bytes) obtained from ICS Ethernet hardware (ex. RAD-STAR)
#define SPY_STATUS2_ETHERNET_NO_PADDING 0x01000000
#define SPY_STATUS2_ETHERNET_PREEMPTION_ENABLED 0x02000000
#define SPY_STATUS2_ETHERNET_UPDATE_CHECKSUMS 0x04000000
#define SPY_STATUS2_ETHERNET_MANUALFCS_ENABLED 0x08000000
#define SPY_STATUS2_ETHERNET_FCS_VERIFIED 0x10000000
#define SPY_STATUS2_ETHERNET_T1S_SYMBOL 0x20000000
#define SPY_STATUS2_ETHERNET_T1S_BURST 0x40000000
#define SPY_STATUS2_ETHERNET_T1S_ETHERNET 0x80000000
// SPYSTATUS2 - FLEXRAY protocol bits
// |----.-xxx|xxxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_FLEXRAY_TX_AB 0x200000
#define SPY_STATUS2_FLEXRAY_TX_AB_NO_A 0x400000
#define SPY_STATUS2_FLEXRAY_TX_AB_NO_B 0x800000
#define SPY_STATUS2_FLEXRAY_TX_AB_NO_MATCH 0x01000000
#define SPY_STATUS2_FLEXRAY_NO_CRC 0x02000000
#define SPY_STATUS2_FLEXRAY_NO_HEADERCRC 0x04000000 //
// SPYSTATUS2 - I2C protocol bits
// |----.----|xxxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_I2C_ERR_TIMEOUT 0x200000
#define SPY_STATUS2_I2C_ERR_NACK 0x400000
#define SPY_STATUS2_I2C_DIR_READ 0x800000
// SPYSTATUS2 - ISO protocol bits
// |-xxx.x---|---o.--oo|----.----|----.oooo|
#define SPY_STATUS2_ISO_FRAME_ERROR 0x08000000 // ISO frame error
#define SPY_STATUS2_ISO_OVERFLOW_ERROR 0x10000000 // ISO overflow error
#define SPY_STATUS2_ISO_PARITY_ERROR 0x20000000 // ISO parity error
#define SPY_STATUS2_ISO_RX_TIMEOUT_ERROR 0x40000000 // ISO specific timeout error
// SPYSTATUS2 - LIN protocol bits
// |xxxx.xxxx|xxxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_LIN_ERR_RX_BREAK_NOT_0 0x200000 // LIN RX break not 0 error
#define SPY_STATUS2_LIN_ERR_RX_BREAK_TOO_SHORT 0x400000 // LIN RX break too short error
#define SPY_STATUS2_LIN_ERR_RX_SYNC_NOT_55 0x800000 // LIN RX sync not 0x55 error
#define SPY_STATUS2_LIN_ERR_RX_DATA_GREATER_8 0x01000000 // LIN RX data greater than 8 bytes error
#define SPY_STATUS2_LIN_ERR_TX_RX_MISMATCH 0x02000000 // LIN TX/RX mismatch error
#define SPY_STATUS2_LIN_ERR_MSG_ID_PARITY 0x04000000 // LIN message ID parity error
#define SPY_STATUS2_LIN_SYNC_FRAME_ERROR 0x08000000 // LIN sync frame error
#define SPY_STATUS2_LIN_ID_FRAME_ERROR 0x10000000 // LIN ID frame error
#define SPY_STATUS2_LIN_SLAVE_BYTE_ERROR 0x20000000 // LIN slave byte error
#define SPY_STATUS2_LIN_RX_TIMEOUT_ERROR 0x40000000 // RX timeout error
#define SPY_STATUS2_LIN_NO_SLAVE_DATA 0x80000000 // LIN no slave data
// SPYSTATUS2 - MDIO protocol bits
// |-xxx.xxxx|xxxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_MDIO_ERR_TIMEOUT 0x200000
#define SPY_STATUS2_MDIO_JOB_CANCELLED 0x400000
#define SPY_STATUS2_MDIO_INVALID_BUS 0x800000
#define SPY_STATUS2_MDIO_INVALID_PHYADDR 0x01000000
#define SPY_STATUS2_MDIO_INVALID_REGADDR 0x02000000
#define SPY_STATUS2_MDIO_UNSUPPORTED_CLAUSE 0x04000000
#define SPY_STATUS2_MDIO_UNSUPPORTED_OPCODE 0x08000000
#define SPY_STATUS2_MDIO_OVERFLOW 0x10000000
#define SPY_STATUS2_MDIO_CLAUSE45 0x20000000
#define SPY_STATUS2_MDIO_READ 0x40000000
// SPYSTATUS2 - MOST protocol bits
// |xxxx.xxxx|xxxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_MOST_PACKET_DATA 0x200000
#define SPY_STATUS2_MOST_STATUS 0x400000 // reflects changes in light/lock/MPR/SBC/etc...
#define SPY_STATUS2_MOST_LOW_LEVEL 0x800000 // MOST low level message, allocs, deallocs, remote requests...*/
#define SPY_STATUS2_MOST_CONTROL_DATA 0x01000000
#define SPY_STATUS2_MOST_MHP_USER_DATA 0x02000000 // MOST HIGH User Data Frame
#define SPY_STATUS2_MOST_MHP_CONTROL_DATA 0x04000000 // MOST HIGH Control Data
#define SPY_STATUS2_MOST_I2S_DUMP 0x08000000
#define SPY_STATUS2_MOST_TOO_SHORT 0x10000000
#define SPY_STATUS2_MOST_MOST50 0x20000000 // absence of MOST50 and MOST150 implies it's MOST25
#define SPY_STATUS2_MOST_MOST150 0x40000000
#define SPY_STATUS2_MOST_CHANGED_PAR 0x80000000 // first byte in ack reflects what changed.
// SPYSTATUS2 - WBMS protocol bits
// |----.----|--xo.--oo|----.----|----.oooo|
#define SPY_STATUS2_WBMS_API_IS_CALLBACK 0x200000
// SPYSTATUS3 bit definitions
// SPYSTATUS3 - CAN protocol bits
// |----.----|-xxx.xxxx|-xxx.xxxx|----.-xxx|
#define SPY_STATUS3_CAN_ERR_PASSIVE 0x01 // CAN error passive state: typically when error counter is > 127
#define SPY_STATUS3_CAN_BUS_OFF 0x02 // CAN bus off state
#define SPY_STATUS3_CAN_ERR_WARNING 0x04 // CAN error warning: typically when error counter is > 96
#define SPY_STATUS3_CAN_DATAERR_STUFF_ERROR 0x0100 // CAN stuff error during the data payload phase
#define SPY_STATUS3_CAN_DATAERR_FORM_ERROR 0x0200 // CAN form error during the data payload phase
#define SPY_STATUS3_CAN_DATAERR_ACK_ERROR 0x0400 // CAN ack error during the data payload phase
#define SPY_STATUS3_CAN_DATAERR_BIT1_ERROR 0x0800 // CAN bit1 error during the data payload phase
#define SPY_STATUS3_CAN_DATAERR_BIT0_ERROR 0x1000 // CAN bit0 error during the data payload phase
#define SPY_STATUS3_CAN_DATAERR_CRC_ERROR 0x2000 // CAN CRC error during the data payload phase
#define SPY_STATUS3_CAN_DATAERR_NOCHANGE 0x4000 // CAN data error occurred before and no change yet
#define SPY_STATUS3_CAN_GENERR_STUFF_ERROR 0x010000 // CAN stuff error at the general frame level
#define SPY_STATUS3_CAN_GENERR_FORM_ERROR 0x020000 // CAN form error at the general frame level
#define SPY_STATUS3_CAN_GENERR_ACK_ERROR 0x040000 // CAN ack error at the general frame level
#define SPY_STATUS3_CAN_GENERR_BIT1_ERROR 0x080000 // CAN bit1 error at the general frame level
#define SPY_STATUS3_CAN_GENERR_BIT0_ERROR 0x100000 // CAN bit0 error at the general frame level
#define SPY_STATUS3_CAN_GENERR_CRC_ERROR 0x200000 // CAN CRC error at the general frame level
#define SPY_STATUS3_CAN_GENERR_NOCHANGE 0x400000 // CAN frame Error occurred before and no change yet
// SPYSTATUS3 - CANFD protocol bits
// |----.----|----.----|----.----|---x.xxxx|
#define SPY_STATUS3_CANFD_ESI 0x01 // CAN FD Error State Indicator (ESI) reflects the error state of the transmitting node
#define SPY_STATUS3_CANFD_IDE 0x02 // CAN FD Identifier Extension (IDE) indicates if standard or extended IDs are in use
#define SPY_STATUS3_CANFD_RTR 0x04
#define SPY_STATUS3_CANFD_FDF 0x08 // CAN FD Format (FDF) flag -- distinguishes classic CAN from CANFD
#define SPY_STATUS3_CANFD_BRS 0x10 // CANFD Baud Rate Select (BRS) flag, indicates if the data portion transmits at a higher bitrate
// SPYSTATUS3 - ETHERNET protocol bits
// |----.----|----.----|----.----|----.--xx|
#define SPY_STATUS3_ETHERNET_TX_COLLISION 0x01
#define SPY_STATUS3_ETHERNET_T1S_WAKE 0x02
// SPYSTATUS3 - LIN protocol bits
// |----.----|----.----|----.----|----.-xxx|
#define SPY_STATUS3_LIN_JUST_BREAK_SYNC 0x01
#define SPY_STATUS3_LIN_SLAVE_DATA_TOO_SHORT 0x02
#define SPY_STATUS3_LIN_ONLY_UPDATE_SLAVE_TABLE_ONCE 0x04
// SPYSTATUS4 bit definitions
// SPYSTATUS4 - ETHERNET protocol bits
// |----.----|----.----|----.----|----.--xx|
#define SPY_STATUS4_ETH_CRC_ERROR 0x01 // Ethernet CRC error
#define SPY_STATUS4_ETH_FRAME_TOO_LONG 0x02 // Ethernet frame too long
#endif // CICSSPYSTATUSBITS_H_
+17
View File
@@ -6,6 +6,22 @@
namespace icsneo { namespace icsneo {
enum class Command : uint8_t { enum class Command : uint8_t {
// Device-originated Main51 event/error notifications (device -> host)
Main51RxBufferOverflow = 0x01,
Main51StartCmd = 0x02,
Main51TxFifoOverflow = 0x03,
Main51BulkInNoData = 0x04,
Main51SetModeComplete = 0x05,
Main51ReadEeprom = 0x06,
// 0x07, 0x08, 0x09 reserved for host->device commands below
Main51CmdDone = 0x0A,
Main51ErrStatus = 0x0B,
Main51ReadSectorBuff = 0x0C,
Main51WriteSectorBuff = 0x0D,
Main51MmcProcessDone = 0x0E,
Main51ReInitDone = 0x0F,
// Host-originated commands (host -> device)
EnableNetworkCommunication = 0x07, EnableNetworkCommunication = 0x07,
EnableNetworkCommunicationEx = 0x08, EnableNetworkCommunicationEx = 0x08,
KeepAlive = 0x09, KeepAlive = 0x09,
@@ -61,6 +77,7 @@ enum class ExtendedCommand : uint16_t {
TransmitCoreminiMessage = 0x0028, TransmitCoreminiMessage = 0x0028,
GenericBinaryInfo = 0x0030, GenericBinaryInfo = 0x0030,
LiveData = 0x0035, LiveData = 0x0035,
ExecuteSPIPortKeyOperation = 0x003C,
RequestTC10Wake = 0x003D, RequestTC10Wake = 0x003D,
RequestTC10Sleep = 0x003E, RequestTC10Sleep = 0x003E,
GetTC10Status = 0x003F, GetTC10Status = 0x003F,
@@ -14,6 +14,7 @@
#include "icsneo/communication/message/extendedresponsemessage.h" #include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/device/deviceversion.h" #include "icsneo/device/deviceversion.h"
#include "icsneo/api/eventmanager.h" #include "icsneo/api/eventmanager.h"
#include "icsneo/api/heartbeat.h"
#include "icsneo/communication/packetizer.h" #include "icsneo/communication/packetizer.h"
#include "icsneo/communication/encoder.h" #include "icsneo/communication/encoder.h"
#include "icsneo/communication/decoder.h" #include "icsneo/communication/decoder.h"
+1 -1
View File
@@ -31,6 +31,7 @@ public:
virtual driver_finder_t getFinder() = 0; virtual driver_finder_t getFinder() = 0;
inline bool isDisconnected() const { return disconnected; }; inline bool isDisconnected() const { return disconnected; };
inline void setIsDisconnected(bool isDisconnected) { disconnected = isDisconnected; }
inline bool isClosing() const { return closing; } inline bool isClosing() const { return closing; }
bool waitForRx(size_t limit, std::chrono::milliseconds timeout); bool waitForRx(size_t limit, std::chrono::milliseconds timeout);
@@ -62,7 +63,6 @@ protected:
}; };
inline void setIsClosing(bool isClosing) { closing = isClosing; } inline void setIsClosing(bool isClosing) { closing = isClosing; }
inline void setIsDisconnected(bool isDisconnected) { disconnected = isDisconnected; }
// Overridable in case the driver doesn't want to use writeTask and writeQueue // Overridable in case the driver doesn't want to use writeTask and writeQueue
virtual bool writeQueueFull() { return writeQueue.size_approx() > writeQueueSize; } virtual bool writeQueueFull() { return writeQueue.size_approx() > writeQueueSize; }
@@ -6,7 +6,6 @@
#include "icsneo/communication/packet/ethphyregpacket.h" #include "icsneo/communication/packet/ethphyregpacket.h"
#include "icsneo/communication/message/message.h" #include "icsneo/communication/message/message.h"
#include "icsneo/communication/packet.h" #include "icsneo/communication/packet.h"
#include "icsneo/api/eventmanager.h"
#include <vector> #include <vector>
#include <memory> #include <memory>
@@ -48,6 +48,7 @@ public:
NetworkMutex = 0x8016, NetworkMutex = 0x8016,
ClientId = 0x8017, ClientId = 0x8017,
AllMACAddresses = 0x8018, AllMACAddresses = 0x8018,
SPIPortKeyOperation = 0x8019,
}; };
Message(Type t) : type(t) {} Message(Type t) : type(t) {}
@@ -0,0 +1,43 @@
#ifndef __SPIPORTKEYMESSAGE_H_
#define __SPIPORTKEYMESSAGE_H_
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
#include <array>
#include <memory>
namespace icsneo {
class SPIPortKeyMessage : public Message {
public:
enum class Operation : uint8_t {
WriteKey = 0,
IsKeySet = 1,
ClearKey = 2
};
#pragma pack(push, 2)
struct SPIPortKeyPacket
{
Operation op;
uint8_t portIndex;
bool isKeyLoaded;
uint8_t rsvd;
uint8_t key[16];
};
#pragma pack(pop)
static std::shared_ptr<SPIPortKeyMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
SPIPortKeyMessage() : Message(Type::SPIPortKeyOperation) {}
bool isKeyLoaded;
};
} // namespace icsneo
#endif // __cplusplus
#endif // __SPIPORTKEYMESSAGE_H_
+1
View File
@@ -126,6 +126,7 @@ enum class ChipID : icsneoc2_chip_id_t {
RADA2B_REVB_ZCHIP = icsneoc2_chip_id_rada2b_revb_zchip, RADA2B_REVB_ZCHIP = icsneoc2_chip_id_rada2b_revb_zchip,
RADGigastar_FFG_ZYNQ = icsneoc2_chip_id_radgigastar_ffg_zynq, RADGigastar_FFG_ZYNQ = icsneoc2_chip_id_radgigastar_ffg_zynq,
VEM_02_FR_FCHIP = icsneoc2_chip_id_vem_02_fr_fchip, VEM_02_FR_FCHIP = icsneoc2_chip_id_vem_02_fr_fchip,
RADBMS_WIL = icsneoc2_chip_id_radbms_wil,
Connect_ZCHIP = icsneoc2_chip_id_connect_zchip, Connect_ZCHIP = icsneoc2_chip_id_connect_zchip,
SFPModule_88q2221_MCHIP = icsneoc2_chip_id_sfpmodule_88q2221_mchip, SFPModule_88q2221_MCHIP = icsneoc2_chip_id_sfpmodule_88q2221_mchip,
RADGALAXY2_SYSMON_CHIP = icsneoc2_chip_id_radgalaxy2_sysmon_chip, RADGALAXY2_SYSMON_CHIP = icsneoc2_chip_id_radgalaxy2_sysmon_chip,
+13 -12
View File
@@ -46,6 +46,7 @@
#include "icsneo/communication/message/extendeddatamessage.h" #include "icsneo/communication/message/extendeddatamessage.h"
#include "icsneo/communication/message/livedatamessage.h" #include "icsneo/communication/message/livedatamessage.h"
#include "icsneo/communication/message/tc10statusmessage.h" #include "icsneo/communication/message/tc10statusmessage.h"
#include "icsneo/communication/message/spiportkeymessage.h"
#include "icsneo/core/macseccfg.h" #include "icsneo/core/macseccfg.h"
#include "icsneo/communication/packet/genericbinarystatuspacket.h" #include "icsneo/communication/packet/genericbinarystatuspacket.h"
#include "icsneo/communication/packet/livedatapacket.h" #include "icsneo/communication/packet/livedatapacket.h"
@@ -133,6 +134,7 @@ public:
RADA2B = 40, RADA2B = 40,
SFPModule_88q2112 = 41, SFPModule_88q2112 = 41,
RADGalaxy2 = 47, RADGalaxy2 = 47,
RADwBMS = 48,
RADMoon3 = 49, RADMoon3 = 49,
RADComet2 = 50, RADComet2 = 50,
Connect = 51, Connect = 51,
@@ -725,6 +727,8 @@ public:
std::optional<EthPhyMessage> sendEthPhyMsg(const EthPhyMessage& message, std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); std::optional<EthPhyMessage> sendEthPhyMsg(const EthPhyMessage& message, std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
bool sendSPIPortKeyOperation(uint8_t portIndex, SPIPortKeyMessage::Operation op, std::array<uint8_t, 16> key = {});
/** /**
* Set the flags of the root directory entry specified at given address * Set the flags of the root directory entry specified at given address
@@ -739,6 +743,7 @@ public:
*/ */
std::optional<bool> SetRootDirectoryEntryFlags(uint8_t mask, uint8_t values, uint32_t collectionEntryByteAddress); std::optional<bool> SetRootDirectoryEntryFlags(uint8_t mask, uint8_t values, uint32_t collectionEntryByteAddress);
device_eventhandler_t report;
std::shared_ptr<Communication> com; std::shared_ptr<Communication> com;
std::shared_ptr<IDeviceSettings> settings; std::shared_ptr<IDeviceSettings> settings;
@@ -896,11 +901,14 @@ public:
bool unlockAllNetworks(); bool unlockAllNetworks();
std::shared_ptr<NetworkMutexMessage> getNetworkMutexStatus(Network::NetID network); std::shared_ptr<NetworkMutexMessage> getNetworkMutexStatus(Network::NetID network);
void startHeartbeat();
void stopHeartbeat();
void restartHeartbeat();
protected: protected:
bool online = false; bool online = false;
int messagePollingCallbackID = 0; int messagePollingCallbackID = 0;
int internalHandlerCallbackID = 0; int internalHandlerCallbackID = 0;
device_eventhandler_t report;
std::mutex ioMutex; std::mutex ioMutex;
std::optional<bool> ethActivationStatus; std::optional<bool> ethActivationStatus;
@@ -933,7 +941,7 @@ protected:
std::move(decoder) std::move(decoder)
); );
setupCommunication(*com); setupCommunication(*com);
settings = makeSettings<Settings>(com); settings = makeSettings<Settings>(this);
setupSettings(*settings); setupSettings(*settings);
diskReadDriver = std::unique_ptr<DiskRead>(new DiskRead()); diskReadDriver = std::unique_ptr<DiskRead>(new DiskRead());
diskWriteDriver = std::unique_ptr<DiskWrite>(new DiskWrite()); diskWriteDriver = std::unique_ptr<DiskWrite>(new DiskWrite());
@@ -969,8 +977,8 @@ protected:
} }
template<typename Settings> template<typename Settings>
std::shared_ptr<IDeviceSettings> makeSettings(std::shared_ptr<Communication> comm) { std::shared_ptr<IDeviceSettings> makeSettings(Device* device) {
return std::make_shared<Settings>(comm); return std::make_shared<Settings>(device);
} }
virtual void setupSettings(IDeviceSettings&) {} virtual void setupSettings(IDeviceSettings&) {}
@@ -1035,10 +1043,6 @@ private:
APIEvent::Type attemptToBeginCommunication(); APIEvent::Type attemptToBeginCommunication();
// Use heartbeatSuppressed instead when reading
std::atomic<int> heartbeatSuppressedByUser{0};
bool heartbeatSuppressed() const { return heartbeatSuppressedByUser > 0 || (settings && settings->applyingSettings); }
void handleNeoVIMessage(std::shared_ptr<CANMessage> message); void handleNeoVIMessage(std::shared_ptr<CANMessage> message);
bool firmwareUpdateSupported(); bool firmwareUpdateSupported();
@@ -1049,10 +1053,6 @@ private:
moodycamel::BlockingConcurrentQueue<std::shared_ptr<Message>> pollingContainer; moodycamel::BlockingConcurrentQueue<std::shared_ptr<Message>> pollingContainer;
void enforcePollingMessageLimit(); void enforcePollingMessageLimit();
std::atomic<bool> stopHeartbeatThread{false};
std::mutex heartbeatMutex;
std::thread heartbeatThread;
std::mutex diskMutex; std::mutex diskMutex;
// Wireless neoVI Stack // Wireless neoVI Stack
@@ -1175,6 +1175,7 @@ private:
// Keeponline (keepalive for online) // Keeponline (keepalive for online)
std::unique_ptr<Periodic> keeponline; std::unique_ptr<Periodic> keeponline;
std::unique_ptr<Heartbeat> heartbeat;
std::optional<uint32_t> assignedClientId; std::optional<uint32_t> assignedClientId;
std::unordered_set<icsneo::Network::NetID> lockedNetworks; std::unordered_set<icsneo::Network::NetID> lockedNetworks;
+4
View File
@@ -52,6 +52,7 @@ public:
RADEpsilon = icsneoc2_devicetype_rad_epsilon, RADEpsilon = icsneoc2_devicetype_rad_epsilon,
RADEpsilonXL = icsneoc2_devicetype_rad_epsilon_xl, RADEpsilonXL = icsneoc2_devicetype_rad_epsilon_xl,
RADGalaxy2 = icsneoc2_devicetype_rad_galaxy2, RADGalaxy2 = icsneoc2_devicetype_rad_galaxy2,
RADwBMS = icsneoc2_devicetype_rad_wbms,
RADMoon3 = icsneoc2_devicetype_rad_moon3, RADMoon3 = icsneoc2_devicetype_rad_moon3,
RADComet2 = icsneoc2_devicetype_rad_comet2, RADComet2 = icsneoc2_devicetype_rad_comet2,
FIRE3_FlexRay = icsneoc2_devicetype_fire3_flexray, FIRE3_FlexRay = icsneoc2_devicetype_fire3_flexray,
@@ -216,6 +217,8 @@ public:
return "neoVI Connect"; return "neoVI Connect";
case RADGigastar2: case RADGigastar2:
return "RAD-Gigastar 2"; return "RAD-Gigastar 2";
case RADwBMS:
return "RAD-wBMS";
case DONT_REUSE0: case DONT_REUSE0:
case DONT_REUSE1: case DONT_REUSE1:
case DONT_REUSE2: case DONT_REUSE2:
@@ -268,6 +271,7 @@ private:
#define ICSNEO_DEVICETYPE_RADEPSILON ((devicetype_t)icsneoc2_devicetype_rad_epsilon) #define ICSNEO_DEVICETYPE_RADEPSILON ((devicetype_t)icsneoc2_devicetype_rad_epsilon)
#define ICSNEO_DEVICETYPE_RADEPSILONXL ((devicetype_t)icsneoc2_devicetype_rad_epsilon_xl) #define ICSNEO_DEVICETYPE_RADEPSILONXL ((devicetype_t)icsneoc2_devicetype_rad_epsilon_xl)
#define ICSNEO_DEVICETYPE_RADGALAXY2 ((devicetype_t)icsneoc2_devicetype_rad_galaxy2) #define ICSNEO_DEVICETYPE_RADGALAXY2 ((devicetype_t)icsneoc2_devicetype_rad_galaxy2)
#define ICSNEO_DEVICETYPE_RADWBMS ((devicetype_t)icsneoc2_devicetype_rad_wbms)
#define ICSNEO_DEVICETYPE_RADMoon3 ((devicetype_t)icsneoc2_devicetype_rad_moon3) #define ICSNEO_DEVICETYPE_RADMoon3 ((devicetype_t)icsneoc2_devicetype_rad_moon3)
#define ICSNEO_DEVICETYPE_RADCOMET2 ((devicetype_t)icsneoc2_devicetype_rad_comet2) #define ICSNEO_DEVICETYPE_RADCOMET2 ((devicetype_t)icsneoc2_devicetype_rad_comet2)
#define ICSNEO_DEVICETYPE_FIRE3FLEXRAY ((devicetype_t)icsneoc2_devicetype_fire3_flexray) #define ICSNEO_DEVICETYPE_FIRE3FLEXRAY ((devicetype_t)icsneoc2_devicetype_fire3_flexray)
+63 -7
View File
@@ -753,16 +753,75 @@ typedef struct
uint16_t cmp_device_id; uint16_t cmp_device_id;
} CMP_GLOBAL_DATA; } CMP_GLOBAL_DATA;
/* wBMS Structs */
typedef union
{
uint8_t byte;
struct
{
uint8_t onboard_external : 1;
uint8_t type : 1;
uint8_t mode: 3;
uint8_t reserved : 3;
} config;
} sSPI_PORT_SETTING;
typedef struct
{
sSPI_PORT_SETTING port_a; //1
sSPI_PORT_SETTING port_b; //1
} sSPI_PORT_SETTINGS;
#define WBMS_GATEWAY_NETWORK_NONE (0)
#define WBMS_GATEWAY_NETWORK_DWCAN_01 (1)
#define WBMS_GATEWAY_NETWORK_DWCAN_02 (2)
#define WBMS_GATEWAY_NETWORK_UDP_MULTICAST (3)
typedef struct
{
uint8_t wbms1_network;
uint8_t wbms1_canfd_enable;
uint8_t wbms2_network;
uint8_t wbms2_canfd_enable;
uint16_t reserved[6];
} WBMSGatewaySettings;
typedef struct
{
uint8_t wBMSDeviceID;
uint8_t enabled;
} sWIL_FAULT_SERVICING_SETTINGS;
typedef struct
{
uint8_t enabled;
} sWIL_NETWORK_DATA_CAPTURE_SETTINGS;
typedef struct
{
uint8_t using_port_a;
uint8_t using_port_b;
uint8_t attemptConnect;
sWIL_FAULT_SERVICING_SETTINGS fault_servicing_config;
sWIL_NETWORK_DATA_CAPTURE_SETTINGS network_data_capture_config;
uint16_t sensor_buffer_size;
} sWIL_CONNECTION_SETTINGS;
#pragma pack(pop) #pragma pack(pop)
#ifdef __cplusplus #ifdef __cplusplus
#include "icsneo/communication/communication.h" #include "icsneo/communication/network.h"
#include "icsneo/api/event.h"
#include "icsneo/api/eventmanager.h"
#include <optional> #include <optional>
#include <iostream> #include <iostream>
#include <atomic> #include <atomic>
namespace icsneo { namespace icsneo {
class Device;
enum class MiscIOAnalogVoltage : uint8_t enum class MiscIOAnalogVoltage : uint8_t
{ {
V0 = icsneoc2_misc_io_analog_voltage_v0, V0 = icsneoc2_misc_io_analog_voltage_v0,
@@ -790,7 +849,7 @@ public:
static int64_t GetBaudrateValueForEnum(CANBaudrate enumValue); static int64_t GetBaudrateValueForEnum(CANBaudrate enumValue);
static bool ValidateLINBaudrate(int64_t baudrate); static bool ValidateLINBaudrate(int64_t baudrate);
IDeviceSettings(std::shared_ptr<Communication> com, size_t size) : com(com), report(com->report), structSize(size) {} IDeviceSettings(Device* device, size_t size);
virtual ~IDeviceSettings() {} virtual ~IDeviceSettings() {}
bool ok() const { return !disabled && settingsLoaded; } bool ok() const { return !disabled && settingsLoaded; }
@@ -1337,10 +1396,8 @@ public:
bool disabled = false; bool disabled = false;
bool readonly = false; bool readonly = false;
std::atomic<bool> applyingSettings{false};
protected: protected:
std::shared_ptr<Communication> com; Device* device;
device_eventhandler_t report; device_eventhandler_t report;
size_t structSize; size_t structSize;
@@ -1352,8 +1409,7 @@ protected:
// Parameter createInoperableSettings exists because it is serving as a warning that you probably don't want to do this // Parameter createInoperableSettings exists because it is serving as a warning that you probably don't want to do this
typedef void* warn_t; typedef void* warn_t;
IDeviceSettings(warn_t createInoperableSettings, std::shared_ptr<Communication> com) IDeviceSettings(warn_t createInoperableSettings, Device* device);
: disabled(true), readonly(true), report(com->report), structSize(0) { (void)createInoperableSettings; }
// Devices that embed a Fire3LinuxSettings block in their settings structure override these to // Devices that embed a Fire3LinuxSettings block in their settings structure override these to
// expose it; all other devices report not-available (nullptr / nullopt) and the Linux accessors // expose it; all other devices report not-available (nullptr / nullopt) and the Linux accessors
+1 -1
View File
@@ -12,7 +12,7 @@ namespace icsneo {
class NullSettings : public IDeviceSettings { class NullSettings : public IDeviceSettings {
public: public:
// Calls the protected base constructor with "createInoperableSettings" // Calls the protected base constructor with "createInoperableSettings"
NullSettings(std::shared_ptr<Communication> com) : IDeviceSettings(nullptr, com) {} NullSettings(Device* device) : IDeviceSettings(nullptr, device) {}
}; };
} }
@@ -69,7 +69,7 @@ static_assert(sizeof(etherbadge_settings_t) == 316, "EtherBadge settings size mi
class EtherBADGESettings : public IDeviceSettings { class EtherBADGESettings : public IDeviceSettings {
public: public:
EtherBADGESettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(etherbadge_settings_t)) {} EtherBADGESettings(Device* device) : IDeviceSettings(device, sizeof(etherbadge_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<etherbadge_settings_t>(); auto cfg = getStructurePointer<etherbadge_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -88,7 +88,7 @@ static_assert(sizeof(neoviconnect_settings_t) == 628, "NeoVIConnect settings siz
class NeoVIConnectSettings : public IDeviceSettings { class NeoVIConnectSettings : public IDeviceSettings {
public: public:
NeoVIConnectSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(neoviconnect_settings_t)) {} NeoVIConnectSettings(Device* device) : IDeviceSettings(device, sizeof(neoviconnect_settings_t)) {}
const Fire3LinuxSettings* getLinuxSettings() const override { const Fire3LinuxSettings* getLinuxSettings() const override {
auto cfg = getStructurePointer<neoviconnect_settings_t>(); auto cfg = getStructurePointer<neoviconnect_settings_t>();
return cfg ? &cfg->os_settings : nullptr; return cfg ? &cfg->os_settings : nullptr;
@@ -101,7 +101,7 @@ static_assert(sizeof(neovifire_settings_t) == 744, "NeoVIFire settings size mism
class NeoVIFIRESettings : public IDeviceSettings { class NeoVIFIRESettings : public IDeviceSettings {
public: public:
NeoVIFIRESettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(neovifire_settings_t)) {} NeoVIFIRESettings(Device* device) : IDeviceSettings(device, sizeof(neovifire_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<neovifire_settings_t>(); auto cfg = getStructurePointer<neovifire_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -125,7 +125,7 @@ static_assert(sizeof(neovifire2_settings_t) == 936, "NeoVIFire2 settings size mi
class NeoVIFIRE2Settings : public IDeviceSettings { class NeoVIFIRE2Settings : public IDeviceSettings {
public: public:
NeoVIFIRE2Settings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(neovifire2_settings_t)) {} NeoVIFIRE2Settings(Device* device) : IDeviceSettings(device, sizeof(neovifire2_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<neovifire2_settings_t>(); auto cfg = getStructurePointer<neovifire2_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -166,7 +166,7 @@ static_assert(sizeof(neovifire3_settings_t) == 1722, "NeoVIFire3 settings size m
class NeoVIFIRE3Settings : public IDeviceSettings { class NeoVIFIRE3Settings : public IDeviceSettings {
public: public:
NeoVIFIRE3Settings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(neovifire3_settings_t)) {} NeoVIFIRE3Settings(Device* device) : IDeviceSettings(device, sizeof(neovifire3_settings_t)) {}
const Fire3LinuxSettings* getLinuxSettings() const override { const Fire3LinuxSettings* getLinuxSettings() const override {
auto cfg = getStructurePointer<neovifire3_settings_t>(); auto cfg = getStructurePointer<neovifire3_settings_t>();
return cfg ? &cfg->os_settings : nullptr; return cfg ? &cfg->os_settings : nullptr;
@@ -149,7 +149,7 @@ static_assert(sizeof(neovifire3flexray_settings_t) == 1372, "NeoVIFire3Flexray s
class NeoVIFIRE3FlexRaySettings : public IDeviceSettings { class NeoVIFIRE3FlexRaySettings : public IDeviceSettings {
public: public:
NeoVIFIRE3FlexRaySettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(neovifire3flexray_settings_t)) {} NeoVIFIRE3FlexRaySettings(Device* device) : IDeviceSettings(device, sizeof(neovifire3flexray_settings_t)) {}
const Fire3LinuxSettings* getLinuxSettings() const override { const Fire3LinuxSettings* getLinuxSettings() const override {
auto cfg = getStructurePointer<neovifire3flexray_settings_t>(); auto cfg = getStructurePointer<neovifire3flexray_settings_t>();
return cfg ? &cfg->os_settings : nullptr; return cfg ? &cfg->os_settings : nullptr;
@@ -158,7 +158,7 @@ static_assert(sizeof(neovifire3t1slin_settings_t) == 1594, "NeoVIFire3T1SLIN set
class NeoVIFIRE3T1SLINSettings : public IDeviceSettings { class NeoVIFIRE3T1SLINSettings : public IDeviceSettings {
public: public:
NeoVIFIRE3T1SLINSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(neovifire3t1slin_settings_t)) {} NeoVIFIRE3T1SLINSettings(Device* device) : IDeviceSettings(device, sizeof(neovifire3t1slin_settings_t)) {}
const Fire3LinuxSettings* getLinuxSettings() const override { const Fire3LinuxSettings* getLinuxSettings() const override {
auto cfg = getStructurePointer<neovifire3t1slin_settings_t>(); auto cfg = getStructurePointer<neovifire3t1slin_settings_t>();
return cfg ? &cfg->os_settings : nullptr; return cfg ? &cfg->os_settings : nullptr;
@@ -111,7 +111,7 @@ static_assert(sizeof(neovired2_settings_t) == 918, "NeoVIRED2 settings size mism
class NeoVIRED2Settings : public IDeviceSettings { class NeoVIRED2Settings : public IDeviceSettings {
public: public:
NeoVIRED2Settings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(neovired2_settings_t)) {} NeoVIRED2Settings(Device* device) : IDeviceSettings(device, sizeof(neovired2_settings_t)) {}
const Fire3LinuxSettings* getLinuxSettings() const override { const Fire3LinuxSettings* getLinuxSettings() const override {
auto cfg = getStructurePointer<neovired2_settings_t>(); auto cfg = getStructurePointer<neovired2_settings_t>();
return cfg ? &cfg->os_settings : nullptr; return cfg ? &cfg->os_settings : nullptr;
@@ -100,7 +100,7 @@ public:
Node Node
}; };
RADA2BSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(rada2b_settings_t)) {} RADA2BSettings(Device* device) : IDeviceSettings(device, sizeof(rada2b_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<rada2b_settings_t>(); auto cfg = getStructurePointer<rada2b_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -141,27 +141,27 @@ public:
} }
} }
TDMMode getTDMMode(RADA2BDevice device) const { TDMMode getTDMMode(RADA2BDevice a2bDevice) const {
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 = a2bDevice == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node;
return static_cast<TDMMode>(deviceSettings.tdmMode); return static_cast<TDMMode>(deviceSettings.tdmMode);
} }
uint8_t getNumChannels(RADA2BDevice device) const { uint8_t getNumChannels(RADA2BDevice a2bDevice) const {
return tdmModeToChannelNum(getTDMMode(device)); return tdmModeToChannelNum(getTDMMode(a2bDevice));
} }
ChannelSize getChannelSize(RADA2BDevice device) const { ChannelSize getChannelSize(RADA2BDevice a2bDevice) const {
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 = a2bDevice == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node;
return static_cast<ChannelSize>(deviceSettings.flags & a2bSettingsFlag16bit); return static_cast<ChannelSize>(deviceSettings.flags & a2bSettingsFlag16bit);
} }
uint8_t getChannelOffset(RADA2BDevice device, A2BMessage::Direction dir) const { uint8_t getChannelOffset(RADA2BDevice a2bDevice, A2BMessage::Direction dir) const {
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 = a2bDevice == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node;
if(dir == A2BMessage::Direction::Upstream) { if(dir == A2BMessage::Direction::Upstream) {
return deviceSettings.upstreamChannelOffset; return deviceSettings.upstreamChannelOffset;
@@ -170,30 +170,30 @@ public:
return deviceSettings.downstreamChannelOffset; return deviceSettings.downstreamChannelOffset;
} }
NodeType getNodeType(RADA2BDevice device) const { NodeType getNodeType(RADA2BDevice a2bDevice) const {
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 = a2bDevice == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node;
return static_cast<NodeType>(deviceSettings.nodeType); return static_cast<NodeType>(deviceSettings.nodeType);
} }
void setNodeType(RADA2BDevice device, NodeType newType) { void setNodeType(RADA2BDevice a2bDevice, NodeType newType) {
auto cfg = getMutableStructurePointer<rada2b_settings_t>(); auto cfg = getMutableStructurePointer<rada2b_settings_t>();
auto &deviceSettings = device == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node; auto &deviceSettings = a2bDevice == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node;
deviceSettings.nodeType = static_cast<uint8_t>(newType); deviceSettings.nodeType = static_cast<uint8_t>(newType);
} }
void setTDMMode(RADA2BDevice device, TDMMode newMode) { void setTDMMode(RADA2BDevice a2bDevice, TDMMode newMode) {
auto cfg = getMutableStructurePointer<rada2b_settings_t>(); auto cfg = getMutableStructurePointer<rada2b_settings_t>();
auto &deviceSettings = device == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node; auto &deviceSettings = a2bDevice == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node;
deviceSettings.tdmMode = static_cast<uint8_t>(newMode); deviceSettings.tdmMode = static_cast<uint8_t>(newMode);
} }
void setChannelOffset(RADA2BDevice device, A2BMessage::Direction dir, uint8_t newOffset) { void setChannelOffset(RADA2BDevice a2bDevice, A2BMessage::Direction dir, uint8_t newOffset) {
auto cfg = getMutableStructurePointer<rada2b_settings_t>(); auto cfg = getMutableStructurePointer<rada2b_settings_t>();
auto &deviceSettings = device == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node; auto &deviceSettings = a2bDevice == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node;
if(dir == A2BMessage::Direction::Upstream) { if(dir == A2BMessage::Direction::Upstream) {
deviceSettings.upstreamChannelOffset = newOffset; deviceSettings.upstreamChannelOffset = newOffset;
@@ -203,9 +203,9 @@ public:
} }
} }
void setChannelSize(RADA2BDevice device, ChannelSize newChannelSize) { void setChannelSize(RADA2BDevice a2bDevice, ChannelSize newChannelSize) {
auto cfg = getMutableStructurePointer<rada2b_settings_t>(); auto cfg = getMutableStructurePointer<rada2b_settings_t>();
auto &deviceSettings = device == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node; auto &deviceSettings = a2bDevice == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node;
if(newChannelSize == ChannelSize::chSize16) { if(newChannelSize == ChannelSize::chSize16) {
deviceSettings.flags |= a2bSettingsFlag16bit; deviceSettings.flags |= a2bSettingsFlag16bit;
@@ -89,7 +89,7 @@ static_assert(sizeof(radcomet2_settings_t) == 498, "RADComet2 settings size mism
class RADComet2Settings : public IDeviceSettings { class RADComet2Settings : public IDeviceSettings {
public: public:
RADComet2Settings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radcomet2_settings_t)) {} RADComet2Settings(Device* device) : IDeviceSettings(device, sizeof(radcomet2_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<radcomet2_settings_t>(); auto cfg = getStructurePointer<radcomet2_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -86,7 +86,7 @@ static_assert(sizeof(radcomet3_settings_t) == 674, "RADComet3 settings size mism
class RADComet3Settings : public IDeviceSettings { class RADComet3Settings : public IDeviceSettings {
public: public:
RADComet3Settings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radcomet3_settings_t)) {} RADComet3Settings(Device* device) : IDeviceSettings(device, sizeof(radcomet3_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<radcomet3_settings_t>(); auto cfg = getStructurePointer<radcomet3_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -86,7 +86,7 @@ static_assert(sizeof(radepsilon_settings_t) == 400, "RADEpsilon settings size mi
class RADEpsilonSettings : public IDeviceSettings { class RADEpsilonSettings : public IDeviceSettings {
public: public:
RADEpsilonSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radepsilon_settings_t)) {} RADEpsilonSettings(Device* device) : IDeviceSettings(device, sizeof(radepsilon_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<radepsilon_settings_t>(); auto cfg = getStructurePointer<radepsilon_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -109,7 +109,7 @@ static_assert(sizeof(radgalaxy_settings_t) == 776, "RADGalaxy settings size mism
class RADGalaxySettings : public IDeviceSettings { class RADGalaxySettings : public IDeviceSettings {
public: public:
RADGalaxySettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radgalaxy_settings_t)) {} RADGalaxySettings(Device* device) : IDeviceSettings(device, sizeof(radgalaxy_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<radgalaxy_settings_t>(); auto cfg = getStructurePointer<radgalaxy_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -125,7 +125,7 @@ static_assert(sizeof(radgalaxy2_settings_t) == 960, "RADGalaxy2 settings size mi
class RADGalaxy2Settings : public IDeviceSettings { class RADGalaxy2Settings : public IDeviceSettings {
public: public:
RADGalaxy2Settings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radgalaxy2_settings_t)) {} RADGalaxy2Settings(Device* device) : IDeviceSettings(device, sizeof(radgalaxy2_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<radgalaxy2_settings_t>(); auto cfg = getStructurePointer<radgalaxy2_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -42,7 +42,7 @@ static_assert(sizeof(radgemini_settings_t) == 86, "RADGemini settings size misma
class RADGeminiSettings : public IDeviceSettings { class RADGeminiSettings : public IDeviceSettings {
public: public:
RADGeminiSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radgemini_settings_t)) {} RADGeminiSettings(Device* device) : IDeviceSettings(device, sizeof(radgemini_settings_t)) {}
}; };
} }
@@ -107,7 +107,7 @@ static_assert(sizeof(radgigastar_settings_t) == 1026, "RADGigastar settings size
class RADGigastarSettings : public IDeviceSettings { class RADGigastarSettings : public IDeviceSettings {
public: public:
RADGigastarSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radgigastar_settings_t)) {} RADGigastarSettings(Device* device) : IDeviceSettings(device, sizeof(radgigastar_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<radgigastar_settings_t>(); auto cfg = getStructurePointer<radgigastar_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -156,7 +156,7 @@ namespace icsneo
class RADGigastar2Settings : public IDeviceSettings class RADGigastar2Settings : public IDeviceSettings
{ {
public: public:
RADGigastar2Settings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radgigastar2_settings_t)) {} RADGigastar2Settings(Device* device) : IDeviceSettings(device, sizeof(radgigastar2_settings_t)) {}
const CAN_SETTINGS *getCANSettingsFor(Network net) const override const CAN_SETTINGS *getCANSettingsFor(Network net) const override
{ {
auto cfg = getStructurePointer<radgigastar2_settings_t>(); auto cfg = getStructurePointer<radgigastar2_settings_t>();
@@ -90,7 +90,7 @@ static_assert(sizeof(radjupiter_settings_t) == 348, "RAD-Jupiter Settings are no
class RADJupiterSettings : public IDeviceSettings { class RADJupiterSettings : public IDeviceSettings {
public: public:
RADJupiterSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radjupiter_settings_t)) {} RADJupiterSettings(Device* device) : IDeviceSettings(device, sizeof(radjupiter_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<radjupiter_settings_t>(); auto cfg = getStructurePointer<radjupiter_settings_t>();
@@ -101,7 +101,7 @@ static_assert(sizeof(radmars_settings_t) == 666, "RAD-Mars settings size mismatc
class RADMarsSettings : public IDeviceSettings { class RADMarsSettings : public IDeviceSettings {
public: public:
RADMarsSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radmars_settings_t)) {} RADMarsSettings(Device* device) : IDeviceSettings(device, sizeof(radmars_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<radmars_settings_t>(); auto cfg = getStructurePointer<radmars_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -42,7 +42,7 @@ static_assert(sizeof(radmoon2_settings_t) == 170, "RADMoon2 settings size mismat
class RADMoon2Settings : public IDeviceSettings { class RADMoon2Settings : public IDeviceSettings {
public: public:
RADMoon2Settings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radmoon2_settings_t)) {} RADMoon2Settings(Device* device) : IDeviceSettings(device, sizeof(radmoon2_settings_t)) {}
const RAD_GPTP_SETTINGS* getGPTPSettings() const override { const RAD_GPTP_SETTINGS* getGPTPSettings() const override {
auto cfg = getStructurePointer<radmoon2_settings_t>(); auto cfg = getStructurePointer<radmoon2_settings_t>();
@@ -39,7 +39,7 @@ static_assert(sizeof(radmoon3_settings_t) == 68, "RADMoon3 settings size mismatc
class RADMoon3Settings : public IDeviceSettings { class RADMoon3Settings : public IDeviceSettings {
public: public:
RADMoon3Settings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radmoon3_settings_t)) {} RADMoon3Settings(Device* device) : IDeviceSettings(device, sizeof(radmoon3_settings_t)) {}
}; };
} }
@@ -55,7 +55,7 @@ static_assert(sizeof(radmoonduo_settings_t) == 38, "RAD-Moon Duo settings size e
class RADMoonDuoSettings : public IDeviceSettings { class RADMoonDuoSettings : public IDeviceSettings {
public: public:
RADMoonDuoSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radmoonduo_settings_t)) {} RADMoonDuoSettings(Device* device) : IDeviceSettings(device, sizeof(radmoonduo_settings_t)) {}
}; };
} }
@@ -46,7 +46,7 @@ static_assert(sizeof(radmoont1s_settings_t) == 160, "RADMoonT1S settings size mi
class RADMoonT1SSettings : public IDeviceSettings { class RADMoonT1SSettings : public IDeviceSettings {
public: public:
RADMoonT1SSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radmoont1s_settings_t)) {} RADMoonT1SSettings(Device* device) : IDeviceSettings(device, sizeof(radmoont1s_settings_t)) {}
std::optional<bool> isT1SPLCAEnabledFor(Network net) const override { std::optional<bool> isT1SPLCAEnabledFor(Network net) const override {
const ETHERNET10T1S_SETTINGS* t1s = getT1SSettingsFor(net); const ETHERNET10T1S_SETTINGS* t1s = getT1SSettingsFor(net);
@@ -74,7 +74,7 @@ static_assert(sizeof(radpluto_settings_t) == 322, "RAD-Pluto Settings are not pa
class RADPlutoSettings : public IDeviceSettings { class RADPlutoSettings : public IDeviceSettings {
public: public:
RADPlutoSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radpluto_settings_t)) { RADPlutoSettings(Device* device) : IDeviceSettings(device, sizeof(radpluto_settings_t)) {
} }
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
@@ -75,7 +75,7 @@ static_assert(sizeof(radstar2_settings_t) == 422, "RADStar2 settings size mismat
class RADStar2Settings : public IDeviceSettings { class RADStar2Settings : public IDeviceSettings {
public: public:
RADStar2Settings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radstar2_settings_t)) { RADStar2Settings(Device* device) : IDeviceSettings(device, sizeof(radstar2_settings_t)) {
} }
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
@@ -38,7 +38,7 @@ typedef struct {
class RADSupermoonSettings : public IDeviceSettings { class RADSupermoonSettings : public IDeviceSettings {
public: public:
RADSupermoonSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radsupermoon_settings_t)) {} RADSupermoonSettings(Device* device) : IDeviceSettings(device, sizeof(radsupermoon_settings_t)) {}
}; };
} }
@@ -0,0 +1,182 @@
#ifndef __RADWBMS_H_
#define __RADWBMS_H_
#include "icsneo/device/device.h"
#include "icsneo/device/devicetype.h"
#include "icsneo/device/tree/radwbms/radwbmssettings.h"
#include "icsneo/disk/neomemorydiskdriver.h"
namespace icsneo {
class RADwBMS : public Device {
public:
enum class FirmwareVariant {
Invalid = 0,
WIL_1_1 = 0x0101000C,
WIL_2_0 = 0x02000058,
WIL_2_0_9_26 = 0x0200091A,
WIL_2_1 = 0x02010047,
WIL_2_2 = 0x0202000F,
WIL_2_3 = 0x0203020B,
WIL_3_1_0_9 = 0x03010009,
WIL_3_2_0 = 0x03020000,
WIL_3_3_0_27 = 0x0303001B,
};
// Serial numbers start with BS
// USB PID is 0x110B, standard driver is CDACM
// Ethernet MAC allocation is 0x1B, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADwBMS, DeviceType::RADwBMS, "BS");
static const std::vector<Network>& GetSupportedNetworks() {
static std::vector<Network> supportedNetworks = {
Network::NetID::DWCAN_01,
Network::NetID::DWCAN_02,
Network::NetID::ETHERNET_01,
};
return supportedNetworks;
}
size_t getEthernetActivationLineCount() const override { return 1; }
bool supportsReboot() const override { return true; }
ProductID getProductID() const override {
return ProductID::RADwBMS;
}
FirmwareVariant variantToFlash = FirmwareVariant::Invalid;
void setVariantToFlash(FirmwareVariant variant) {
variantToFlash = variant;
}
FirmwareVariant getCurrentVariant() {
if(supportsComponentVersions()) {
refreshComponentVersions();
const auto& components = getComponentVersions();
for(const auto& component : components) {
if(!component.valid) {
continue;
}
if(component.identifier == static_cast<uint32_t>(ChipID::RADBMS_WIL)) {
FirmwareVariant res = FirmwareVariant::Invalid;
switch(static_cast<FirmwareVariant>(component.dotVersion)) {
case FirmwareVariant::WIL_1_1:
case FirmwareVariant::WIL_2_0:
case FirmwareVariant::WIL_2_0_9_26:
case FirmwareVariant::WIL_2_1:
case FirmwareVariant::WIL_2_2:
case FirmwareVariant::WIL_2_3:
case FirmwareVariant::WIL_3_1_0_9:
case FirmwareVariant::WIL_3_2_0:
case FirmwareVariant::WIL_3_3_0_27:
res = static_cast<FirmwareVariant>(component.dotVersion);
break;
default:
res = FirmwareVariant::Invalid;
break;
}
if(variantToFlash == FirmwareVariant::Invalid) {
// Set the variantToFlash if it hasn't been set yet, we always flash the same firmware variant as the current if it is unspecified
variantToFlash = res;
}
return res;
}
}
}
return FirmwareVariant::Invalid;
}
const std::vector<ChipInfo>& getChipInfo() const override {
switch (variantToFlash) {
case FirmwareVariant::WIL_1_1: {
static std::vector<ChipInfo> chips = {{ChipID::RADBMS_MCHIP, true, "MCHIP", "rad_bms_mchip_WIL_1_1_ief", 0, FirmwareType::IEF}};
return chips;
}
case FirmwareVariant::WIL_2_0: {
static std::vector<ChipInfo> chips = {{ChipID::RADBMS_MCHIP, true, "MCHIP", "rad_bms_mchip_WIL_2_0_ief", 0, FirmwareType::IEF}};
return chips;
}
case FirmwareVariant::WIL_2_0_9_26: {
static std::vector<ChipInfo> chips = {{ChipID::RADBMS_MCHIP, true, "MCHIP", "rad_bms_mchip_WIL_2_0_9_26_ief", 0, FirmwareType::IEF}};
return chips;
}
case FirmwareVariant::WIL_2_1: {
static std::vector<ChipInfo> chips = {{ChipID::RADBMS_MCHIP, true, "MCHIP", "rad_bms_mchip_WIL_2_1_ief", 0, FirmwareType::IEF}};
return chips;
}
case FirmwareVariant::WIL_2_2: {
static std::vector<ChipInfo> chips = {{ChipID::RADBMS_MCHIP, true, "MCHIP", "rad_bms_mchip_WIL_2_2_ief", 0, FirmwareType::IEF}};
return chips;
}
case FirmwareVariant::WIL_2_3: {
static std::vector<ChipInfo> chips = {{ChipID::RADBMS_MCHIP, true, "MCHIP", "rad_bms_mchip_WIL_2_3_ief", 0, FirmwareType::IEF}};
return chips;
}
case FirmwareVariant::WIL_3_1_0_9: {
static std::vector<ChipInfo> chips = {{ChipID::RADBMS_MCHIP, true, "MCHIP", "rad_bms_mchip_WIL_3_1_0_9_ief", 0, FirmwareType::IEF}};
return chips;
}
case FirmwareVariant::WIL_3_2_0: {
static std::vector<ChipInfo> chips = {{ChipID::RADBMS_MCHIP, true, "MCHIP", "rad_bms_mchip_WIL_3_2_0_ief", 0, FirmwareType::IEF}};
return chips;
}
case FirmwareVariant::WIL_3_3_0_27: {
static std::vector<ChipInfo> chips = {{ChipID::RADBMS_MCHIP, true, "MCHIP", "rad_bms_mchip_WIL_3_3_0_27_ief", 0, FirmwareType::IEF}};
return chips;
}
case FirmwareVariant::Invalid:
break; // invalid will be handled below
}
// Return empty chip information if the WIL version is not set
static std::vector<ChipInfo> chips = {};
return chips;
}
BootloaderPipeline getBootloader() override {
return BootloaderPipeline()
.add<EnterBootloaderPhase>()
.add<FlashPhase>(ChipID::RADBMS_MCHIP, BootloaderCommunication::RED)
.add<EnterApplicationPhase>(ChipID::RADBMS_MCHIP)
.add<WaitPhase>(std::chrono::milliseconds(3000))
.add<ReconnectPhase>();
}
std::vector<VersionReport> getChipVersions(bool refreshComponents = true) override {
if(variantToFlash == FirmwareVariant::Invalid) {
getCurrentVariant();
}
return Device::getChipVersions(refreshComponents);
}
protected:
RADwBMS(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<RADwBMSSettings, Disk::NeoMemoryDiskDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
}
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
for(auto& netid : GetSupportedNetworks())
rxNetworks.emplace_back(netid);
}
// The supported TX networks are the same as the supported RX networks for this device
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
std::optional<MemoryAddress> getCoreminiStartAddressFlash() const override {
return 2048 * 512;
}
std::optional<MemoryAddress> getCoreminiStartAddressSD() const override {
return 0;
}
bool supportsEraseMemory() const override {
return true;
}
};
}; // namespace icsneo
#endif // __RADWBMS_H_
@@ -0,0 +1,80 @@
#ifndef __RADWBMSSETTINGS_H_
#define __RADWBMSSETTINGS_H_
#include <stdint.h>
#include "icsneo/device/idevicesettings.h"
#ifdef __cplusplus
namespace icsneo {
#endif // __cplusplus
#pragma pack(push, 2)
typedef struct
{
uint16_t perf_en;
uint64_t termination_enables;
CAN_SETTINGS can1;
CANFD_SETTINGS canfd1;
CAN_SETTINGS can2;
CANFD_SETTINGS canfd2;
uint16_t network_enables;
uint16_t network_enables_2;
uint16_t network_enables_3;
int16_t iso15765_separation_time_offset;
struct
{
uint32_t disableUsbCheckOnBoot : 1;
uint32_t enableLatencyTest : 1;
uint32_t enablePcEthernetComm : 1;
uint32_t reserved : 29;
} flags;
ETHERNET_SETTINGS ethernet;
ETHERNET_SETTINGS2 ethernet2;
uint32_t pwr_man_timeout;
uint16_t pwr_man_enable;
uint16_t network_enabled_on_boot;
uint8_t rsvd[10]; //Was sWILBridgeConfig
sSPI_PORT_SETTINGS spi_config;
sWIL_CONNECTION_SETTINGS wbms_wil_1;
sWIL_CONNECTION_SETTINGS wbms_wil_2;
uint16_t wil1_nwk_metadata_buff_count;
uint16_t wil2_nwk_metadata_buff_count;
WBMSGatewaySettings gateway;
uint16_t network_enables_4;
uint64_t network_enables_5;
} radwbms_settings_t;
#pragma pack(pop)
#ifdef __cplusplus
static_assert(sizeof(radwbms_settings_t) == 156, "RAD-wBMS settings size mismatch");
#include <iostream>
class RADwBMSSettings : public IDeviceSettings {
public:
RADwBMSSettings(Device* device) : IDeviceSettings(device, sizeof(radwbms_settings_t)) {}
};
}
#endif // __cplusplus
#endif // __RADWBMSSETTINGS_H_
@@ -37,7 +37,7 @@ static_assert(sizeof(valuecan3_settings_t) == 40, "ValueCAN3 settings size misma
class ValueCAN3Settings : public IDeviceSettings { class ValueCAN3Settings : public IDeviceSettings {
public: public:
ValueCAN3Settings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(valuecan3_settings_t)) {} ValueCAN3Settings(Device* device) : IDeviceSettings(device, sizeof(valuecan3_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<valuecan3_settings_t>(); auto cfg = getStructurePointer<valuecan3_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -10,7 +10,7 @@ namespace icsneo {
class ValueCAN4_1_2Settings : public IDeviceSettings { class ValueCAN4_1_2Settings : public IDeviceSettings {
public: public:
ValueCAN4_1_2Settings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(valuecan4_1_2_settings_t)) {} ValueCAN4_1_2Settings(Device* device) : IDeviceSettings(device, sizeof(valuecan4_1_2_settings_t)) {}
// We do not override getCANSettingsFor or getCANFDSettingsFor here because they will be device specific // We do not override getCANSettingsFor or getCANFDSettingsFor here because they will be device specific
}; };
@@ -9,7 +9,7 @@ namespace icsneo {
class ValueCAN4_1Settings : public ValueCAN4_1_2Settings { class ValueCAN4_1Settings : public ValueCAN4_1_2Settings {
public: public:
ValueCAN4_1Settings(std::shared_ptr<Communication> com) : ValueCAN4_1_2Settings(com) {} ValueCAN4_1Settings(Device* device) : ValueCAN4_1_2Settings(device) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<valuecan4_1_2_settings_t>(); auto cfg = getStructurePointer<valuecan4_1_2_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -10,7 +10,7 @@ namespace icsneo {
class ValueCAN4_2ELSettings : public ValueCAN4_4_2ELSettings { class ValueCAN4_2ELSettings : public ValueCAN4_4_2ELSettings {
public: public:
ValueCAN4_2ELSettings(std::shared_ptr<Communication> com) : ValueCAN4_4_2ELSettings(com) {} ValueCAN4_2ELSettings(Device* device) : ValueCAN4_4_2ELSettings(device) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<valuecan4_4_2el_settings_t>(); auto cfg = getStructurePointer<valuecan4_4_2el_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -9,7 +9,7 @@ namespace icsneo {
class ValueCAN4_2Settings : public ValueCAN4_1_2Settings { class ValueCAN4_2Settings : public ValueCAN4_1_2Settings {
public: public:
ValueCAN4_2Settings(std::shared_ptr<Communication> com) : ValueCAN4_1_2Settings(com) {} ValueCAN4_2Settings(Device* device) : ValueCAN4_1_2Settings(device) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<valuecan4_1_2_settings_t>(); auto cfg = getStructurePointer<valuecan4_1_2_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -10,7 +10,7 @@ namespace icsneo {
class ValueCAN4_4_2ELSettings : public IDeviceSettings { class ValueCAN4_4_2ELSettings : public IDeviceSettings {
public: public:
ValueCAN4_4_2ELSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(valuecan4_4_2el_settings_t)) {} ValueCAN4_4_2ELSettings(Device* device) : IDeviceSettings(device, sizeof(valuecan4_4_2el_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<valuecan4_4_2el_settings_t>(); auto cfg = getStructurePointer<valuecan4_4_2el_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -10,7 +10,7 @@ namespace icsneo {
class ValueCAN4_4Settings : public ValueCAN4_4_2ELSettings { class ValueCAN4_4Settings : public ValueCAN4_4_2ELSettings {
public: public:
ValueCAN4_4Settings(std::shared_ptr<Communication> com) : ValueCAN4_4_2ELSettings(com) {} ValueCAN4_4Settings(Device* device) : ValueCAN4_4_2ELSettings(device) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<valuecan4_4_2el_settings_t>(); auto cfg = getStructurePointer<valuecan4_4_2el_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -10,7 +10,7 @@ namespace icsneo {
class ValueCAN4IndustrialSettings : public IDeviceSettings { class ValueCAN4IndustrialSettings : public IDeviceSettings {
public: public:
ValueCAN4IndustrialSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(valuecan4_industrial_settings_t)) {} ValueCAN4IndustrialSettings(Device* device) : IDeviceSettings(device, sizeof(valuecan4_industrial_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<valuecan4_industrial_settings_t>(); auto cfg = getStructurePointer<valuecan4_industrial_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -48,7 +48,7 @@ static_assert(sizeof(vividcan_settings_t) == 64, "VividCAN settings size mismatc
class VividCANSettings : public IDeviceSettings { class VividCANSettings : public IDeviceSettings {
public: public:
VividCANSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(vividcan_settings_t)) {} VividCANSettings(Device* device) : IDeviceSettings(device, sizeof(vividcan_settings_t)) {}
const CAN_SETTINGS* getCANSettingsFor(Network net) const override { const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
auto cfg = getStructurePointer<vividcan_settings_t>(); auto cfg = getStructurePointer<vividcan_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
+1513 -1672
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -372,10 +372,11 @@ icsneoc2_error_t icsneoc2_device_mac_addresses_enumerate(const icsneoc2_device_t
* *
* @param[in] mac_address The MAC address object to get the network ID of. * @param[in] mac_address The MAC address object to get the network ID of.
* @param[out] network_id Pointer to an icsneoc2_netid_t to copy the network ID into. * @param[out] network_id Pointer to an icsneoc2_netid_t to copy the network ID into.
* Unrecognized values are normalized to icsneoc2_netid_invalid.
* *
* @return icsneoc2_error_t icsneoc2_error success if successful, icsneoc2_error_invalid_parameters on failure. * @return icsneoc2_error_t icsneoc2_error success if successful, icsneoc2_error_invalid_parameters on failure.
*/ */
icsneoc2_error_t icsneoc2_mac_network_id_get(const icsneoc2_mac_addr_entry_t* mac_address, _icsneoc2_netid_t* network_id); icsneoc2_error_t icsneoc2_mac_network_id_get(const icsneoc2_mac_addr_entry_t* mac_address, icsneoc2_netid_t* network_id);
/** /**
* Get the MAC Address bytes of a MAC address. * Get the MAC Address bytes of a MAC address.
+55 -1
View File
@@ -140,7 +140,61 @@ icsneoc2_error_t icsneoc2_settings_termination_is_enabled(icsneoc2_device_t* dev
*/ */
icsneoc2_error_t icsneoc2_settings_termination_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool enable); icsneoc2_error_t icsneoc2_settings_termination_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool enable);
// TODO: getTerminationGroups /**
* Enumerate the termination groups for a device.
*
* Some devices have groupings of networks where software switchable termination
* can only be applied to one network in the group at a time. This enumerates
* those groups. Use icsneoc2_termination_group_next() to walk the list and
* icsneoc2_termination_group_networks_get() to read each group's networks.
*
* These groups apply to the CAN termination controlled by the
* icsneoc2_settings_termination_* functions. 10BASE-T1S termination
* (icsneoc2_settings_t1s_*) is per-network and is never grouped.
*
* If the device does not support software switchable termination, the list is
* empty (*groups is set to NULL and *count, if provided, is set to 0).
*
* @param[in] device The device to query.
* @param[out] groups Receives a newly allocated termination group handle, or NULL if there are no groups. The caller owns this handle and must free it with icsneoc2_settings_termination_groups_free() when done.
* @param[out] count Receives the number of termination groups. May be NULL if not needed.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_out_of_memory otherwise.
*/
icsneoc2_error_t icsneoc2_settings_termination_groups_enumerate(icsneoc2_device_t* device, icsneoc2_termination_group_t** groups, size_t* count);
/**
* Advance to the next termination group in an enumeration list.
*
* @param[in] group The current termination group handle.
*
* @return The next termination group handle, or NULL at the end of the list.
*/
icsneoc2_termination_group_t* icsneoc2_termination_group_next(const icsneoc2_termination_group_t* group);
/**
* Get the networks belonging to a termination group.
*
* Call with networks set to NULL to query the number of networks in the group;
* *count will be set to the required size. Then call again with a buffer of at
* least that size. On success *count is updated with the number of netids written.
*
* @param[in] group The termination group handle to query.
* @param[out] networks Pointer to a buffer to copy the group's netids into. May be NULL to query the required size.
* @param[in,out] count On input, the capacity of the networks buffer. On output, the number of netids written (or required, if networks is NULL).
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_termination_group_networks_get(const icsneoc2_termination_group_t* group, icsneoc2_netid_t* networks, size_t* count);
/**
* Free a termination group list returned by icsneoc2_settings_termination_groups_enumerate().
*
* @param[in] groups The termination group handle to free. Passing NULL returns icsneoc2_error_invalid_parameters.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_settings_termination_groups_free(icsneoc2_termination_group_t* groups);
/** /**
* Check if the commander resistor is currently enabled for a network. * Check if the commander resistor is currently enabled for a network.
+4
View File
@@ -42,6 +42,7 @@ typedef enum _icsneoc2_devicetype_t {
icsneoc2_devicetype_rad_epsilon = 0x00000018, icsneoc2_devicetype_rad_epsilon = 0x00000018,
icsneoc2_devicetype_rad_epsilon_xl = 0x0000001e, icsneoc2_devicetype_rad_epsilon_xl = 0x0000001e,
icsneoc2_devicetype_rad_galaxy2 = 0x00000021, icsneoc2_devicetype_rad_galaxy2 = 0x00000021,
icsneoc2_devicetype_rad_wbms = 0x00000022,
icsneoc2_devicetype_rad_moon3 = 0x00000023, icsneoc2_devicetype_rad_moon3 = 0x00000023,
icsneoc2_devicetype_rad_comet2 = 0x00000024, icsneoc2_devicetype_rad_comet2 = 0x00000024,
icsneoc2_devicetype_fire3_flexray = 0x00000025, icsneoc2_devicetype_fire3_flexray = 0x00000025,
@@ -546,6 +547,8 @@ typedef uint8_t icsneoc2_tc10_sleep_status_t;
typedef struct icsneoc2_chip_versions_t icsneoc2_chip_versions_t; typedef struct icsneoc2_chip_versions_t icsneoc2_chip_versions_t;
typedef struct icsneoc2_termination_group_t icsneoc2_termination_group_t;
typedef enum _icsneoc2_chip_id_t { typedef enum _icsneoc2_chip_id_t {
icsneoc2_chip_id_neovifire_mchip = 0, icsneoc2_chip_id_neovifire_mchip = 0,
icsneoc2_chip_id_neovifire_lchip = 1, icsneoc2_chip_id_neovifire_lchip = 1,
@@ -663,6 +666,7 @@ typedef enum _icsneoc2_chip_id_t {
icsneoc2_chip_id_rada2b_revb_zchip = 116, icsneoc2_chip_id_rada2b_revb_zchip = 116,
icsneoc2_chip_id_radgigastar_ffg_zynq = 117, icsneoc2_chip_id_radgigastar_ffg_zynq = 117,
icsneoc2_chip_id_vem_02_fr_fchip = 118, icsneoc2_chip_id_vem_02_fr_fchip = 118,
icsneoc2_chip_id_radbms_wil = 119,
icsneoc2_chip_id_connect_zchip = 121, icsneoc2_chip_id_connect_zchip = 121,
icsneoc2_chip_id_sfpmodule_88q2221_mchip = 122, icsneoc2_chip_id_sfpmodule_88q2221_mchip = 122,
icsneoc2_chip_id_radgalaxy2_sysmon_chip = 123, icsneoc2_chip_id_radgalaxy2_sysmon_chip = 123,
+21
View File
@@ -9,6 +9,27 @@
typedef uint8_t byte; // Typedef helper for the following include typedef uint8_t byte; // Typedef helper for the following include
#include "icsneo/icsnVC40.h" // Definitions for structs #include "icsneo/icsnVC40.h" // Definitions for structs
// Vehicle Spy 3.26.3.9 removed these legacy settings structure definitions from
// icsnVC40.h. The corresponding functions only ever treat them as opaque
// buffers, so forward declarations keep the existing API/ABI intact.
typedef struct _SFireSettings SFireSettings;
typedef struct _SVCAN3Settings SVCAN3Settings;
typedef struct _SVCANRFSettings SVCANRFSettings;
// Vehicle Spy 3.26.3.9 moved icsSpyTime out of icsnVC40.h; icsneoGetRTC and
// icsneoSetRTC access its members, so the definition (identical layout, 6
// bytes) is carried here.
typedef struct
{
uint8_t sec; // --- Seconds (00-59)
uint8_t min; // --- (00-59)
uint8_t hour; // --- (00-23)
uint8_t day; // --- (01-31)
uint8_t month; // --- (01-12)
uint8_t year; // --- (00-99)
} icsSpyTime;
#define icsSpyTime_SIZE 6
// From coremini.h // From coremini.h
#define MAX_BIT_SMASH_ARBIDS (4) #define MAX_BIT_SMASH_ARBIDS (4)
#define BIT_SMASH_OPTION_EXTENDED (1) #define BIT_SMASH_OPTION_EXTENDED (1)
+1
View File
@@ -33,6 +33,7 @@
#include "icsneo/device/tree/radpluto/radpluto.h" #include "icsneo/device/tree/radpluto/radpluto.h"
#include "icsneo/device/tree/radstar2/radstar2.h" #include "icsneo/device/tree/radstar2/radstar2.h"
#include "icsneo/device/tree/radsupermoon/radsupermoon.h" #include "icsneo/device/tree/radsupermoon/radsupermoon.h"
#include "icsneo/device/tree/radwbms/radwbms.h"
#include "icsneo/device/tree/valuecan3/valuecan3.h" #include "icsneo/device/tree/valuecan3/valuecan3.h"
#include "icsneo/device/tree/valuecan4/valuecan4-1.h" #include "icsneo/device/tree/valuecan4/valuecan4-1.h"
#include "icsneo/device/tree/valuecan4/valuecan4-2.h" #include "icsneo/device/tree/valuecan4/valuecan4-2.h"
@@ -33,6 +33,7 @@
#include "icsneo/device/tree/radpluto/radpluto.h" #include "icsneo/device/tree/radpluto/radpluto.h"
#include "icsneo/device/tree/radstar2/radstar2.h" #include "icsneo/device/tree/radstar2/radstar2.h"
#include "icsneo/device/tree/radsupermoon/radsupermoon.h" #include "icsneo/device/tree/radsupermoon/radsupermoon.h"
#include "icsneo/device/tree/radwbms/radwbms.h"
#include "icsneo/device/tree/valuecan3/valuecan3.h" #include "icsneo/device/tree/valuecan3/valuecan3.h"
#include "icsneo/device/tree/valuecan4/valuecan4-1.h" #include "icsneo/device/tree/valuecan4/valuecan4-1.h"
#include "icsneo/device/tree/valuecan4/valuecan4-2.h" #include "icsneo/device/tree/valuecan4/valuecan4-2.h"
+5 -1
View File
@@ -243,6 +243,7 @@ bool Servd::enableCommunication(bool enable, bool& sendMsg) {
} }
void Servd::read() { void Servd::read() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
std::vector<uint8_t> buf(2 * 1024 * 1024); std::vector<uint8_t> buf(2 * 1024 * 1024);
while(!isDisconnected() && !isClosing()) { while(!isDisconnected() && !isClosing()) {
bool hasData; bool hasData;
@@ -260,11 +261,14 @@ void Servd::read() {
setIsDisconnected(true); setIsDisconnected(true);
return; return;
} }
pushRx(buf.data(), bufSize); if(!pushRx(buf.data(), bufSize)) {
EventManager::GetInstance().add(APIEvent::Type::FailedToRead, APIEvent::Severity::Error);
}
} }
} }
void Servd::write() { void Servd::write() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
WriteOperation writeOp; WriteOperation writeOp;
while(!isDisconnected() && !isClosing()) { while(!isDisconnected() && !isClosing()) {
if(!writeQueue.wait_dequeue_timed(writeOp, std::chrono::milliseconds(100))) { if(!writeQueue.wait_dequeue_timed(writeOp, std::chrono::milliseconds(100))) {
+112
View File
@@ -127,6 +127,28 @@ TEST(icsneoc2, test_icsneoc2_device_is_valid)
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_is_valid(NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_is_valid(NULL));
} }
TEST(icsneoc2, test_icsneoc2_mac_address_get_query_length)
{
icsneoc2_mac_addr_entry_t mac_address = {};
size_t value_length = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_mac_address_get(&mac_address, NULL, &value_length));
ASSERT_EQ(ICSNEO_MAC_ADDRESS_LEN, value_length);
}
TEST(icsneoc2, test_icsneoc2_mac_address_get_truncated_length)
{
icsneoc2_mac_addr_entry_t mac_address = {};
const uint8_t expected[ICSNEO_MAC_ADDRESS_LEN] = {0x00, 0xFC, 0x70, 0x1E, 0x18, 0x70};
std::copy(std::begin(expected), std::end(expected), mac_address.address);
uint8_t value[3] = {};
size_t value_length = sizeof(value);
ASSERT_EQ(icsneoc2_error_success, icsneoc2_mac_address_get(&mac_address, value, &value_length));
ASSERT_EQ(sizeof(value), value_length);
ASSERT_EQ(0, memcmp(expected, value, sizeof(value)));
}
TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device) TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device)
{ {
bool placeholderBool = false; bool placeholderBool = false;
@@ -261,6 +283,13 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device)
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_termination_can_enable(NULL, 0, &placeholderBool)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_termination_can_enable(NULL, 0, &placeholderBool));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_termination_is_enabled(NULL, 0, &placeholderBool)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_termination_is_enabled(NULL, 0, &placeholderBool));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_termination_set(NULL, 0, false)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_termination_set(NULL, 0, false));
{
icsneoc2_termination_group_t* placeholderGroups = nullptr;
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_termination_groups_enumerate(NULL, &placeholderGroups, &placeholderSizeT));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_termination_group_networks_get(NULL, NULL, &placeholderSizeT));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_termination_groups_free(NULL));
ASSERT_EQ(nullptr, icsneoc2_termination_group_next(NULL));
}
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_commander_resistor_enabled(NULL, 0, &placeholderBool)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_commander_resistor_enabled(NULL, 0, &placeholderBool));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_commander_resistor_set(NULL, 0, false)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_commander_resistor_set(NULL, 0, false));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_lin_mode_get(NULL, 0, &placeholderLinMode)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_lin_mode_get(NULL, 0, &placeholderLinMode));
@@ -1143,6 +1172,64 @@ TEST(icsneoc2, test_icsneoc2_chip_versions_free_list)
ASSERT_EQ(icsneoc2_error_success, icsneoc2_chip_versions_free(head)); ASSERT_EQ(icsneoc2_error_success, icsneoc2_chip_versions_free(head));
} }
TEST(icsneoc2, test_icsneoc2_termination_group_walk_and_networks)
{
// Build an in-memory list of two termination groups:
// group A: { DWCAN_01, DWCAN_02 }
// group B: { DWCAN_03 }
icsneoc2_termination_group_t second{};
second.netids = { icsneoc2_netid_dwcan_03 };
second.next = nullptr;
icsneoc2_termination_group_t first{};
first.netids = { icsneoc2_netid_dwcan_01, icsneoc2_netid_dwcan_02 };
first.next = &second;
// next() walks the list
ASSERT_EQ(&second, icsneoc2_termination_group_next(&first));
ASSERT_EQ(nullptr, icsneoc2_termination_group_next(&second));
// networks_get with NULL buffer reports the required count
size_t count = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_termination_group_networks_get(&first, NULL, &count));
ASSERT_EQ(count, 2u);
// networks_get fills the buffer and updates count
icsneoc2_netid_t netids[2] = {0, 0};
count = 2;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_termination_group_networks_get(&first, netids, &count));
ASSERT_EQ(count, 2u);
ASSERT_EQ(netids[0], icsneoc2_netid_dwcan_01);
ASSERT_EQ(netids[1], icsneoc2_netid_dwcan_02);
// second group has a single network
count = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_termination_group_networks_get(&second, NULL, &count));
ASSERT_EQ(count, 1u);
// a buffer smaller than the group truncates to capacity
icsneoc2_netid_t one[1] = {0};
count = 1;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_termination_group_networks_get(&first, one, &count));
ASSERT_EQ(count, 1u);
ASSERT_EQ(one[0], icsneoc2_netid_dwcan_01);
}
TEST(icsneoc2, test_icsneoc2_termination_groups_free_list)
{
// Allocate a two-node list the same way the API does, so free() walks and deletes it.
auto* head = new icsneoc2_termination_group_t{};
head->netids = { icsneoc2_netid_dwcan_01 };
head->next = new icsneoc2_termination_group_t{};
head->next->netids = { icsneoc2_netid_dwcan_02 };
head->next->next = nullptr;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_settings_termination_groups_free(head));
// Freeing an empty (NULL) list returns invalid_parameters, matching chip_versions_free.
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_settings_termination_groups_free(nullptr));
}
TEST(icsneoc2, test_icsneoc2_open_options_default) TEST(icsneoc2, test_icsneoc2_open_options_default)
{ {
icsneoc2_open_options_t expected = ICSNEOC2_OPEN_OPTIONS_GO_ONLINE | ICSNEOC2_OPEN_OPTIONS_SYNC_RTC | ICSNEOC2_OPEN_OPTIONS_ENABLE_AUTO_UPDATE; icsneoc2_open_options_t expected = ICSNEOC2_OPEN_OPTIONS_GO_ONLINE | ICSNEOC2_OPEN_OPTIONS_SYNC_RTC | ICSNEOC2_OPEN_OPTIONS_ENABLE_AUTO_UPDATE;
@@ -2066,3 +2153,28 @@ TEST(icsneoc2, test_gptp_enum_alignment)
ASSERT_EQ(sizeof(RADGPTPRole), sizeof(icsneoc2_gptp_role_t)); ASSERT_EQ(sizeof(RADGPTPRole), sizeof(icsneoc2_gptp_role_t));
} }
TEST(icsneoc2, test_mac_network_id_get)
{
icsneoc2_mac_addr_entry_t entry {};
icsneoc2_netid_t network_id = 0;
entry.network_id = icsneoc2_netid_ethernet_01;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_mac_network_id_get(&entry, &network_id));
ASSERT_EQ(icsneoc2_netid_ethernet_01, network_id);
entry.network_id = 43;
network_id = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_mac_network_id_get(&entry, &network_id));
ASSERT_EQ(icsneoc2_netid_invalid, network_id);
entry.network_id = icsneoc2_netid_invalid;
network_id = 0;
ASSERT_EQ(icsneoc2_error_success, icsneoc2_mac_network_id_get(&entry, &network_id));
ASSERT_EQ(icsneoc2_netid_invalid, network_id);
ASSERT_EQ(icsneoc2_error_invalid_parameters,
icsneoc2_mac_network_id_get(nullptr, &network_id));
ASSERT_EQ(icsneoc2_error_invalid_parameters,
icsneoc2_mac_network_id_get(&entry, nullptr));
}