diff --git a/CMakeLists.txt b/CMakeLists.txt index 7207c946..97ef81d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,6 +230,7 @@ set(SRC_FILES communication/message/logdatamessage.cpp communication/message/tc10statusmessage.cpp communication/message/gptpstatusmessage.cpp + communication/message/allmacaddressesmessage.cpp communication/message/ethernetstatusmessage.cpp communication/message/networkmutexmessage.cpp communication/message/clientidmessage.cpp diff --git a/api/icsneoc2/icsneoc2.cpp b/api/icsneoc2/icsneoc2.cpp index 66374d5b..d82aebc0 100644 --- a/api/icsneoc2/icsneoc2.cpp +++ b/api/icsneoc2/icsneoc2.cpp @@ -14,6 +14,7 @@ #include #include #include +#include using namespace icsneo; @@ -458,27 +459,78 @@ icsneoc2_error_t icsneoc2_device_pcb_serial_get(const icsneoc2_device_t* device, return icsneoc2_error_success; } -icsneoc2_error_t icsneoc2_device_mac_address_get(const icsneoc2_device_t* device, uint8_t* value, size_t* value_length) { +icsneoc2_error_t icsneoc2_device_mac_addresses_enumerate(const icsneoc2_device_t* device, icsneoc2_mac_addr_entry_t** mac_entries) { auto res = icsneoc2_device_is_valid(device); if(res != icsneoc2_error_success) { return res; } - if(!value_length) { + if(!mac_entries) { return icsneoc2_error_invalid_parameters; } - auto macAddress = device->device->getMACAddress(); - if(!macAddress.has_value()) { + const auto result = device->device->getMACAddresses(); + if(result.empty()) { return icsneoc2_error_invalid_type; } - const auto& data = *macAddress; - if(value) { - size_t copyLen = std::min(*value_length, data.size()); - std::copy(data.begin(), data.begin() + copyLen, value); + icsneoc2_mac_addr_entry_t* head = nullptr; + icsneoc2_mac_addr_entry_t* tail = nullptr; + for(auto addr_pair : result) { + auto* node = new (std::nothrow) icsneoc2_mac_addr_entry_t; + if(!node) { + icsneoc2_mac_addresses_free(head); + return icsneoc2_error_out_of_memory; + } + node->network_id = static_cast(addr_pair.first); + std::copy(addr_pair.second.begin(), addr_pair.second.end(), node->address); + node->next = nullptr; + if(!head) { + head = node; + } else { + tail->next = node; + } + tail = node; } - *value_length = data.size(); 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) { + if(!mac_address || !network_id) { + return icsneoc2_error_invalid_parameters; + } + *network_id = static_cast<_icsneoc2_netid_t>(mac_address->network_id); + 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) { + if(!mac_address || !value || !value_length) { + return icsneoc2_error_invalid_parameters; + } + if(value) { + size_t copyLen = std::min(*value_length, static_cast(ICSNEO_MAC_ADDRESS_LEN)); + std::copy(mac_address->address, mac_address->address + copyLen, value); + } + *value_length = static_cast(ICSNEO_MAC_ADDRESS_LEN); + return icsneoc2_error_success; +} + +icsneoc2_mac_addr_entry_t* icsneoc2_mac_addresses_next(const icsneoc2_mac_addr_entry_t* mac_address) { + if(!mac_address) { + return nullptr; + } + return mac_address->next; +} + +icsneoc2_error_t icsneoc2_mac_addresses_free(icsneoc2_mac_addr_entry_t* mac_address) { + if(!mac_address) { + return icsneoc2_error_invalid_parameters; + } + + while(mac_address) { + auto* next = mac_address->next; + delete mac_address; + mac_address = next; + } + return icsneoc2_error_success; +} icsneoc2_error_t icsneoc2_device_go_online(const icsneoc2_device_t* device, bool go_online) { auto res = icsneoc2_device_is_valid(device); diff --git a/api/icsneoc2/icsneoc2_internal.h b/api/icsneoc2/icsneoc2_internal.h index 5dca710c..9ee83081 100644 --- a/api/icsneoc2/icsneoc2_internal.h +++ b/api/icsneoc2/icsneoc2_internal.h @@ -48,6 +48,12 @@ typedef struct icsneoc2_chip_versions_t { icsneoc2_chip_versions_t* next; } icsneoc2_chip_versions_t; +typedef struct icsneoc2_mac_addr_entry_t { + uint16_t network_id; + uint8_t address[ICSNEO_MAC_ADDRESS_LEN]; + icsneoc2_mac_addr_entry_t* next; +} icsneoc2_mac_addr_entry_t; + /** * Safely copies a std::string to a char array. * diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt index e38c90cc..cf9433fc 100644 --- a/bindings/python/CMakeLists.txt +++ b/bindings/python/CMakeLists.txt @@ -31,6 +31,7 @@ pybind11_add_module(icsneopy icsneopy/communication/message/tc10statusmessage.cpp icsneopy/communication/message/mdiomessage.cpp icsneopy/communication/message/gptpstatusmessage.cpp + icsneopy/communication/message/allmacaddressesmessage.cpp icsneopy/communication/message/ethernetstatusmessage.cpp icsneopy/communication/message/spimessage.cpp icsneopy/communication/message/scriptstatusmessage.cpp diff --git a/bindings/python/icsneopy/communication/message/allmacaddressesmessage.cpp b/bindings/python/icsneopy/communication/message/allmacaddressesmessage.cpp new file mode 100644 index 00000000..d32a9b76 --- /dev/null +++ b/bindings/python/icsneopy/communication/message/allmacaddressesmessage.cpp @@ -0,0 +1,13 @@ +#include +#include + +#include "icsneo/communication/message/allmacaddressesmessage.h" + +namespace icsneo { + +void init_allmacaddressesmessage(pybind11::module_& m) { + pybind11::classh(m, "AllMACAddressesMessage") + .def_readonly("addresses", &AllMACAddressesMessage::addresses); +} + +} // namespace icsneo diff --git a/bindings/python/icsneopy/device/device.cpp b/bindings/python/icsneopy/device/device.cpp index 39f18dd2..fde0bd3e 100644 --- a/bindings/python/icsneopy/device/device.cpp +++ b/bindings/python/icsneopy/device/device.cpp @@ -33,7 +33,7 @@ void init_device(pybind11::module_& m) { .def("get_serial_number", &Device::getSerialNumber) .def("get_serial", &Device::getSerial) .def("get_pcb_serial", &Device::getPCBSerial, pybind11::call_guard()) - .def("get_mac_address", &Device::getMACAddress, pybind11::call_guard()) + .def("get_mac_addresses", &Device::getMACAddresses, pybind11::call_guard()) .def("get_supported_rx_networks", &Device::getSupportedRXNetworks, pybind11::return_value_policy::reference) .def("get_supported_tx_networks", &Device::getSupportedTXNetworks, pybind11::return_value_policy::reference) .def("get_tc10_status", &Device::getTC10Status, pybind11::call_guard()) diff --git a/bindings/python/icsneopy/icsneocpp.cpp b/bindings/python/icsneopy/icsneocpp.cpp index ce23edc5..35338931 100644 --- a/bindings/python/icsneopy/icsneocpp.cpp +++ b/bindings/python/icsneopy/icsneocpp.cpp @@ -19,6 +19,7 @@ void init_ethernetmessage(pybind11::module_&); void init_linmessage(pybind11::module_&); void init_tc10statusmessage(pybind11::module_&); void init_gptpstatusmessage(pybind11::module_&); +void init_allmacaddressesmessage(pybind11::module_&); void init_mdiomessage(pybind11::module_&); void init_spimessage(pybind11::module_&); void init_ethernetstatusmessage(pybind11::module_&); @@ -59,6 +60,7 @@ PYBIND11_MODULE(icsneopy, m) { init_linmessage(m); init_tc10statusmessage(m); init_gptpstatusmessage(m); + init_allmacaddressesmessage(m); init_mdiomessage(m); init_ethernetstatusmessage(m); init_macsecconfig(m); diff --git a/communication/decoder.cpp b/communication/decoder.cpp index 4b85f676..8642f871 100644 --- a/communication/decoder.cpp +++ b/communication/decoder.cpp @@ -21,6 +21,7 @@ #include "icsneo/communication/message/hardwareinfo.h" #include "icsneo/communication/message/tc10statusmessage.h" #include "icsneo/communication/message/gptpstatusmessage.h" +#include "icsneo/communication/message/allmacaddressesmessage.h" #include "icsneo/communication/message/apperrormessage.h" #include "icsneo/communication/message/ethernetstatusmessage.h" #include "icsneo/communication/message/networkmutexmessage.h" @@ -343,6 +344,9 @@ bool Decoder::decode(std::shared_ptr& result, const std::shared_ptrdata); return true; + case ExtendedCommand::GetAllMACAddresses: + result = AllMACAddressesMessage::DecodeToMessage(packet->data); + return true; case ExtendedCommand::GetGPTPStatus: { result = GPTPStatus::DecodeToMessage(packet->data, report); return true; diff --git a/communication/message/allmacaddressesmessage.cpp b/communication/message/allmacaddressesmessage.cpp new file mode 100644 index 00000000..a41594e2 --- /dev/null +++ b/communication/message/allmacaddressesmessage.cpp @@ -0,0 +1,51 @@ +#include "icsneo/communication/message/allmacaddressesmessage.h" +#include "icsneo/communication/command.h" +#include "icsneo/communication/network.h" + +#include + +using namespace icsneo; + +#pragma pack(push, 2) +struct ResponseHeader { + ExtendedCommand command; + uint16_t length; + uint16_t count; +}; + +struct MacAddrEntryPacket { + uint16_t networkId; + uint8_t address[MACAddressLength]; +}; +#pragma pack(pop) + +std::shared_ptr AllMACAddressesMessage::DecodeToMessage(const std::vector& bytestream) { + if(bytestream.size() < sizeof(ResponseHeader)) + return nullptr; + + const auto* hdr = reinterpret_cast(bytestream.data()); + + if(hdr->command != ExtendedCommand::GetAllMACAddresses) + return nullptr; + + if(hdr->count > MaxMACAddressCount) + return nullptr; + + const size_t required = sizeof(ResponseHeader) + hdr->count * sizeof(MacAddrEntryPacket); + if(bytestream.size() < required) + return nullptr; + + auto msg = std::make_shared(); + + const auto* entries = reinterpret_cast(bytestream.data() + sizeof(ResponseHeader)); + for(uint16_t i = 0; i < hdr->count; ++i) { + // The firmware sends CoreMini network IDs — convert to NetID for consistent use in libicsneo + Network::NetID netId = Network::GetNetIDFromCoreMiniNetwork(static_cast(entries[i].networkId)); + auto addr = entries[i].address; + MACAddress arrAddr; + std::copy(addr, addr + MACAddressLength, arrAddr.begin()); + msg->addresses.emplace(std::make_pair(netId, arrAddr)); + } + + return msg; +} diff --git a/device/device.cpp b/device/device.cpp index 99341457..ae4fc163 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -2263,13 +2263,34 @@ std::optional> Device::getPCBSerial() { return std::vector(serialMsg->pcbSerial, serialMsg->pcbSerial + sizeof(serialMsg->pcbSerial)); } -std::optional> Device::getMACAddress() { - auto serialMsg = com->getSerialNumberSync(); - if(!serialMsg || !serialMsg->hasMacAddress) { - return std::nullopt; +std::unordered_map Device::getMACAddresses() { + if(supportsGetAllMACAddresses()) { + if(!isOpen()) { + report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error); + return {}; + } + auto msg = com->waitForMessageSync( + [this](){ return com->sendCommand(ExtendedCommand::GetAllMACAddresses, {}); }, + std::make_shared(Message::Type::AllMACAddresses), + std::chrono::milliseconds(100) + ); + if(msg) { + const auto typed = std::dynamic_pointer_cast(msg); + if(typed) + return typed->addresses; + } } - return std::vector(serialMsg->macAddress, serialMsg->macAddress + sizeof(serialMsg->macAddress)); + auto serialMsg = com->getSerialNumberSync(); + if(!serialMsg || !serialMsg->hasMacAddress) + return {}; + + std::unordered_map addresses; + auto addr = serialMsg->macAddress; + MACAddress arrAddr; + std::copy(addr, addr + MACAddressLength, arrAddr.begin()); + addresses.emplace(std::make_pair(Network::NetID::ETHERNET_01, arrAddr)); + return addresses; } std::optional> Device::getSupportedFeatures() { diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index fa1ffd70..8ecc74b5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -15,6 +15,7 @@ option(LIBICSNEO_BUILD_C2_ETHERNET_RECEIVE_EXAMPLE "Build the C2 ethernet receiv option(LIBICSNEO_BUILD_C2_T1S_LOOPBACK_EXAMPLE "Build the C2 RAD-Comet3 T1S loopback example." ON) option(LIBICSNEO_BUILD_C2_TC10_EXAMPLE "Build the C2 TC10 example." ON) option(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE "Build the simple C++ example." ON) +option(LIBICSNEO_BUILD_CPP_DEVICE_INFO_EXAMPLE "Build the C++ device info example." ON) option(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON) option(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE "Build the A2B example." ON) option(LIBICSNEO_BUILD_CPP_LIN_EXAMPLE "Build the LIN example." ON) @@ -101,6 +102,10 @@ if(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE) add_subdirectory(cpp/simple) endif() +if(LIBICSNEO_BUILD_CPP_DEVICE_INFO_EXAMPLE) + add_subdirectory(cpp/device_info) +endif() + if(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE) add_subdirectory(cpp/interactive) endif() diff --git a/examples/c2/device_info/src/main.c b/examples/c2/device_info/src/main.c index 02a645a5..1e387226 100644 --- a/examples/c2/device_info/src/main.c +++ b/examples/c2/device_info/src/main.c @@ -102,19 +102,31 @@ int main() { print_error_code("Failed to get PCB serial (device may not support it)", res); } - /* ===== MAC Address ===== */ - uint8_t mac[6] = {0}; - size_t mac_len = sizeof(mac); - res = icsneoc2_device_mac_address_get(device, mac, &mac_len); + /* ===== MAC Addresses ===== */ + icsneoc2_mac_addr_entry_t* macs = NULL; + res = icsneoc2_device_mac_addresses_enumerate(device, &macs); if(res == icsneoc2_error_success) { - printf("MAC: "); - for(size_t i = 0; i < mac_len; i++) { - if(i > 0) printf(":"); - printf("%02X", mac[i]); + uint16_t mac_count = 0; + for(icsneoc2_mac_addr_entry_t* cur = macs; cur; cur = icsneoc2_mac_addresses_next(cur)) { + mac_count++; } - printf("\n"); + 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)) { + _icsneoc2_netid_t network_id; + icsneoc2_mac_network_id_get(cur, &network_id); + printf(" Network %-5u ", (unsigned)network_id); + uint8_t address[6]; + size_t address_size = 6; + icsneoc2_mac_address_get(cur, address, &address_size); + for(int j = 0; j < 6; j++) { + if(j > 0) printf(":"); + printf("%02X", (unsigned)address[j]); + } + printf("\n"); + } + icsneoc2_mac_addresses_free(macs); } else { - print_error_code("Failed to get MAC address (device may not support it)", res); + print_error_code("Failed to get MAC addresses (device may not support it)", res); } /* Cleanup */ diff --git a/examples/cpp/device_info/CMakeLists.txt b/examples/cpp/device_info/CMakeLists.txt new file mode 100644 index 00000000..f4f4d247 --- /dev/null +++ b/examples/cpp/device_info/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(libicsneocpp-device-info-example src/DeviceInfoExample.cpp) +target_link_libraries(libicsneocpp-device-info-example icsneocpp) diff --git a/examples/cpp/device_info/src/DeviceInfoExample.cpp b/examples/cpp/device_info/src/DeviceInfoExample.cpp new file mode 100644 index 00000000..9295455f --- /dev/null +++ b/examples/cpp/device_info/src/DeviceInfoExample.cpp @@ -0,0 +1,80 @@ +#include +#include +#include + +#include "icsneo/icsneocpp.h" + +static std::string formatMAC(const std::array addr) { + std::ostringstream oss; + for(size_t i = 0; i < icsneo::MACAddressLength; i++) { + if(i > 0) { + oss << ':'; + } + oss << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast(addr[i]); + } + return oss.str(); +} + +int main() { + // ===== Device Selection ===== + std::cout << "Searching for devices...\n"; + auto devices = icsneo::FindAllDevices(); + + if(devices.empty()) { + std::cout << "No devices found.\n"; + return 1; + } + + for(size_t i = 0; i < devices.size(); i++) { + std::cout << " [" << (i + 1) << "] " << devices[i]->describe() << "\n"; + } + + int choice; + std::cout << "Select device (1-" << devices.size() << "): "; + if(!(std::cin >> choice) || choice < 1 || choice > (int)devices.size()) { + std::cout << "Invalid selection.\n"; + return 1; + } + + auto& device = devices[choice - 1]; + + std::cout << "\nOpening " << device->describe() << "... "; + if(!device->open()) { + std::cout << "FAIL\n" << icsneo::GetLastError() << "\n"; + return 1; + } + std::cout << "OK\n\n"; + + // ===== Serial Number ===== + std::cout << "Serial: " << device->getSerial() << "\n"; + + // ===== PCB Serial Number ===== + auto pcbSerial = device->getPCBSerial(); + if(pcbSerial.has_value()) { + std::cout << "PCB Serial: "; + for(auto b : *pcbSerial) + std::cout << (char)b; + std::cout << "\n"; + } else { + std::cout << "PCB Serial: Not supported\n"; + } + + auto macs = device->getMACAddresses(); + if(!macs.empty()) { + std::cout << "MACs: " << macs.size() + << (macs.size() == 1 ? " entry" : " entries") << "\n"; + for(auto macPair : macs) { + std::cout << " " << std::left << std::setw(20) + << icsneo::Network::GetNetIDString(static_cast(macPair.first)) + << " " << formatMAC(macPair.second) << "\n"; + } + } else { + std::cout << "MACs: Not supported\n"; + } + + // ===== Cleanup ===== + std::cout << "\nClosing device... "; + std::cout << (device->close() ? "OK" : "FAIL") << "\n"; + + return 0; +} diff --git a/include/icsneo/communication/command.h b/include/icsneo/communication/command.h index 1e7fb16c..21e93df7 100644 --- a/include/icsneo/communication/command.h +++ b/include/icsneo/communication/command.h @@ -64,6 +64,7 @@ enum class ExtendedCommand : uint16_t { RequestTC10Wake = 0x003D, RequestTC10Sleep = 0x003E, GetTC10Status = 0x003F, + GetAllMACAddresses = 0x0040, ProtobufAPI = 0x0041, TransmitMessage = 0x0042, }; diff --git a/include/icsneo/communication/message/allmacaddressesmessage.h b/include/icsneo/communication/message/allmacaddressesmessage.h new file mode 100644 index 00000000..494d1540 --- /dev/null +++ b/include/icsneo/communication/message/allmacaddressesmessage.h @@ -0,0 +1,35 @@ +#ifndef __ALLMACADDRESSESMESSAGE_H_ +#define __ALLMACADDRESSESMESSAGE_H_ + +#define ICSNEO_MAC_ADDRESS_LEN 6 +#define ICSNEO_MAX_MAC_COUNT 32 + +#ifdef __cplusplus + +#include "icsneo/communication/message/message.h" + +#include +#include +#include +#include +namespace icsneo { + +static constexpr uint16_t MaxMACAddressCount = ICSNEO_MAX_MAC_COUNT; +static constexpr uint8_t MACAddressLength = ICSNEO_MAC_ADDRESS_LEN; + +using MACAddress = std::array; + +class AllMACAddressesMessage : public Message { +public: + static std::shared_ptr DecodeToMessage(const std::vector& bytestream); + + AllMACAddressesMessage() : Message(Type::AllMACAddresses) {} + + std::unordered_map addresses; +}; + +} // namespace icsneo + +#endif // __cplusplus + +#endif // __ALLMACADDRESSESMESSAGE_H_ diff --git a/include/icsneo/communication/message/message.h b/include/icsneo/communication/message/message.h index 1c22164e..a1ecd6a2 100644 --- a/include/icsneo/communication/message/message.h +++ b/include/icsneo/communication/message/message.h @@ -47,6 +47,7 @@ public: LogData = 0x8015, NetworkMutex = 0x8016, ClientId = 0x8017, + AllMACAddresses = 0x8018, }; Message(Type t) : type(t) {} diff --git a/include/icsneo/device/device.h b/include/icsneo/device/device.h index 248544af..59cc9e99 100644 --- a/include/icsneo/device/device.h +++ b/include/icsneo/device/device.h @@ -59,6 +59,7 @@ #include "icsneo/communication/message/versionmessage.h" #include "icsneo/communication/message/gptpstatusmessage.h" #include "icsneo/communication/message/networkmutexmessage.h" +#include "icsneo/communication/message/allmacaddressesmessage.h" #define ICSNEO_FINDABLE_DEVICE_BASE(className, type) \ static constexpr DeviceType::Enum DEVICE_TYPE = type; \ @@ -183,7 +184,7 @@ public: std::string getSerial() const { return data.serial; } uint32_t getSerialNumber() const { return Device::SerialStringToNum(getSerial()); } std::optional> getPCBSerial(); - std::optional> getMACAddress(); + std::unordered_map getMACAddresses(); const neodevice_t& getNeoDevice() const { return data; } virtual std::string getProductName() const { return getType().getGenericProductName(); } std::string describe() const; @@ -858,7 +859,7 @@ public: } virtual bool supportsTC10() const { return false; } - + virtual bool supportsGPTP() const { return false; } bool requestTC10Wake(Network::NetID network); @@ -998,6 +999,8 @@ protected: bool supportsNetworkMutex = false; + virtual bool supportsGetAllMACAddresses() const { return true; } + private: neodevice_t data; std::shared_ptr latestResetStatus; diff --git a/include/icsneo/device/tree/etherbadge/etherbadge.h b/include/icsneo/device/tree/etherbadge/etherbadge.h index 665270b5..b0da4668 100644 --- a/include/icsneo/device/tree/etherbadge/etherbadge.h +++ b/include/icsneo/device/tree/etherbadge/etherbadge.h @@ -62,6 +62,9 @@ protected: return true; } + bool supportsGetAllMACAddresses() const override { + return false; + } }; } diff --git a/include/icsneo/device/tree/neoobd2pro/neoobd2pro.h b/include/icsneo/device/tree/neoobd2pro/neoobd2pro.h index a81c1302..6628e03a 100644 --- a/include/icsneo/device/tree/neoobd2pro/neoobd2pro.h +++ b/include/icsneo/device/tree/neoobd2pro/neoobd2pro.h @@ -26,6 +26,11 @@ public: return ProductID::neoOBD2Pro; } +protected: + bool supportsGetAllMACAddresses() const override { + return false; + } + private: NeoOBD2PRO(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { initialize(makeDriver); diff --git a/include/icsneo/device/tree/neoobd2sim/neoobd2sim.h b/include/icsneo/device/tree/neoobd2sim/neoobd2sim.h index 46d74f7f..38c5924b 100644 --- a/include/icsneo/device/tree/neoobd2sim/neoobd2sim.h +++ b/include/icsneo/device/tree/neoobd2sim/neoobd2sim.h @@ -25,6 +25,12 @@ public: ProductID getProductID() const override { return ProductID::neoOBD2Sim; } + +protected: + bool supportsGetAllMACAddresses() const override { + return false; + } + private: NeoOBD2SIM(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { initialize(makeDriver); diff --git a/include/icsneo/device/tree/neoviconnect/neoviconnect.h b/include/icsneo/device/tree/neoviconnect/neoviconnect.h index 5982d10b..65da5dc3 100644 --- a/include/icsneo/device/tree/neoviconnect/neoviconnect.h +++ b/include/icsneo/device/tree/neoviconnect/neoviconnect.h @@ -93,7 +93,6 @@ protected: } bool supportsGPTP() const override { return true; } - size_t getDiskCount() const override { return 2; } diff --git a/include/icsneo/device/tree/neovifire/neovifire.h b/include/icsneo/device/tree/neovifire/neovifire.h index 1ac7eaa8..28a7bd5d 100644 --- a/include/icsneo/device/tree/neovifire/neovifire.h +++ b/include/icsneo/device/tree/neovifire/neovifire.h @@ -60,6 +60,12 @@ public: ProductID getProductID() const override { return ProductID::neoVIFIRE; } + +protected: + bool supportsGetAllMACAddresses() const override { + return false; + } + private: NeoVIFIRE(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { initialize(makeDriver); diff --git a/include/icsneo/device/tree/neovifire3flexray/neovifire3flexray.h b/include/icsneo/device/tree/neovifire3flexray/neovifire3flexray.h index ef830eed..3f315c0d 100644 --- a/include/icsneo/device/tree/neovifire3flexray/neovifire3flexray.h +++ b/include/icsneo/device/tree/neovifire3flexray/neovifire3flexray.h @@ -109,7 +109,7 @@ protected: void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } bool supportsWiVI() const override { return true; } - + bool supportsLiveData() const override { return true; } std::optional getCoreminiStartAddressFlash() const override { diff --git a/include/icsneo/device/tree/plasion/plasion.h b/include/icsneo/device/tree/plasion/plasion.h index 8fcae8fb..29c3e68d 100644 --- a/include/icsneo/device/tree/plasion/plasion.h +++ b/include/icsneo/device/tree/plasion/plasion.h @@ -92,6 +92,10 @@ protected: } bool supportsWiVI() const override { return true; } + + bool supportsGetAllMACAddresses() const override { + return false; + } }; } diff --git a/include/icsneo/device/tree/radepsilon/radepsilon.h b/include/icsneo/device/tree/radepsilon/radepsilon.h index 8c26dd52..7f9f6897 100644 --- a/include/icsneo/device/tree/radepsilon/radepsilon.h +++ b/include/icsneo/device/tree/radepsilon/radepsilon.h @@ -79,6 +79,10 @@ protected: size_t getDiskCount() const override { return 1; } + + bool supportsGetAllMACAddresses() const override { + return false; + } }; } diff --git a/include/icsneo/device/tree/radepsilonxl/radepsilonxl.h b/include/icsneo/device/tree/radepsilonxl/radepsilonxl.h index 73ecc4fd..6bbbb1a7 100644 --- a/include/icsneo/device/tree/radepsilonxl/radepsilonxl.h +++ b/include/icsneo/device/tree/radepsilonxl/radepsilonxl.h @@ -85,6 +85,10 @@ protected: size_t getDiskCount() const override { return 1; } + + bool supportsGetAllMACAddresses() const override { + return false; + } }; }; // namespace icsneo diff --git a/include/icsneo/device/tree/radjupiter/radjupiter.h b/include/icsneo/device/tree/radjupiter/radjupiter.h index 5690dbc3..23fa83a1 100644 --- a/include/icsneo/device/tree/radjupiter/radjupiter.h +++ b/include/icsneo/device/tree/radjupiter/radjupiter.h @@ -80,6 +80,10 @@ protected: bool supportsEraseMemory() const override { return true; } + + bool supportsGetAllMACAddresses() const override { + return false; + } }; } diff --git a/include/icsneo/device/tree/radmoonduo/radmoonduo.h b/include/icsneo/device/tree/radmoonduo/radmoonduo.h index 553cbe88..2afcc0df 100644 --- a/include/icsneo/device/tree/radmoonduo/radmoonduo.h +++ b/include/icsneo/device/tree/radmoonduo/radmoonduo.h @@ -60,6 +60,10 @@ protected: bool supportsEraseMemory() const override { return true; } + + bool supportsGetAllMACAddresses() const override { + return false; + } }; } diff --git a/include/icsneo/device/tree/radstar2/radstar2.h b/include/icsneo/device/tree/radstar2/radstar2.h index 93bc47d4..d1cec567 100644 --- a/include/icsneo/device/tree/radstar2/radstar2.h +++ b/include/icsneo/device/tree/radstar2/radstar2.h @@ -71,6 +71,10 @@ protected: std::optional getCoreminiStartAddressSD() const override { return 0; } + + bool supportsGetAllMACAddresses() const override { + return false; + } }; } diff --git a/include/icsneo/device/tree/valuecan3/valuecan3.h b/include/icsneo/device/tree/valuecan3/valuecan3.h index 7b4985d9..048f2ae1 100644 --- a/include/icsneo/device/tree/valuecan3/valuecan3.h +++ b/include/icsneo/device/tree/valuecan3/valuecan3.h @@ -25,6 +25,11 @@ public: ProductID getProductID() const override { return ProductID::ValueCAN3; } + +protected: + bool supportsGetAllMACAddresses() const override { + return false; + } private: ValueCAN3(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { initialize(makeDriver); diff --git a/include/icsneo/device/tree/valuecan4/valuecan4.h b/include/icsneo/device/tree/valuecan4/valuecan4.h index 81ee7e01..982420ff 100644 --- a/include/icsneo/device/tree/valuecan4/valuecan4.h +++ b/include/icsneo/device/tree/valuecan4/valuecan4.h @@ -28,6 +28,10 @@ protected: std::optional getCoreminiStartAddressSD() const override { return 0; } + + bool supportsGetAllMACAddresses() const override { + return false; + } }; } diff --git a/include/icsneo/device/tree/vividcan/vividcan.h b/include/icsneo/device/tree/vividcan/vividcan.h index 236e5a15..2fbf78c8 100644 --- a/include/icsneo/device/tree/vividcan/vividcan.h +++ b/include/icsneo/device/tree/vividcan/vividcan.h @@ -68,6 +68,10 @@ protected: bool supportsEraseMemory() const override { return true; } + + bool supportsGetAllMACAddresses() const override { + return false; + } }; } diff --git a/include/icsneo/icsneoc2.h b/include/icsneo/icsneoc2.h index e3827cca..8209eeaf 100644 --- a/include/icsneo/icsneoc2.h +++ b/include/icsneo/icsneoc2.h @@ -343,15 +343,52 @@ icsneoc2_error_t icsneoc2_device_serial_get(const icsneoc2_device_t* device, cha icsneoc2_error_t icsneoc2_device_pcb_serial_get(const icsneoc2_device_t* device, uint8_t* value, size_t* value_length); /** - * Get the MAC address of a device. + * Enumerate MAC addresses from a device. * - * @param[in] device The device to get the MAC address of. - * @param[out] value Pointer to a buffer to copy the MAC address into. If NULL, only value_length is written. - * @param[in,out] value_length Size of the value buffer in bytes. Modified with the length of the MAC address. + * @param[in] device The device to query. + * @param[out] mac_entries Pointer to receive the head of the MAC addresses linked list. * - * @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_type if the device does not have a MAC address. + * @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters on failure. */ -icsneoc2_error_t icsneoc2_device_mac_address_get(const icsneoc2_device_t* device, uint8_t* value, size_t* value_length); +icsneoc2_error_t icsneoc2_device_mac_addresses_enumerate(const icsneoc2_device_t* device, icsneoc2_mac_addr_entry_t** mac_entries); + +/** + * Get the network ID of a MAC address. + * + * @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. + * + * @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); + +/** + * Get the MAC Address bytes of a MAC address. + * + * @param[in] mac_address The MAC address object to get the MAC address bytes of. + * @param[out] value Pointer to a buffer to copy the MAC address into. If NULL, only value_length is written. + * + * @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters on failure. + */ +icsneoc2_error_t icsneoc2_mac_address_get(const icsneoc2_mac_addr_entry_t* mac_address, uint8_t* value, size_t* value_length); + +/** + * Advance to the next MAC address in an enumeration list. + * + * @param[in] mac_address The current MAC address node. + * + * @return icsneoc2_mac_addr_entry_t The next MAC address node. + */ +icsneoc2_mac_addr_entry_t* icsneoc2_mac_addresses_next(const icsneoc2_mac_addr_entry_t* mac_address); + +/** + * Free all MAC addresses in enumeration handle returned by icsneoc2_device_mac_addresses_enumerate(). + * + * @param[in] mac_address The head of the MAC address enumeration to free. May be NULL. + * + * @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise. + */ +icsneoc2_error_t icsneoc2_mac_addresses_free(icsneoc2_mac_addr_entry_t* mac_address); /** * Set the online state of a device. diff --git a/include/icsneo/icsneoc2types.h b/include/icsneo/icsneoc2types.h index c2be77a1..67e96a6e 100644 --- a/include/icsneo/icsneoc2types.h +++ b/include/icsneo/icsneoc2types.h @@ -583,6 +583,8 @@ typedef enum _icsneoc2_chip_id_t { typedef uint8_t icsneoc2_chip_id_t; +typedef struct icsneoc2_mac_addr_entry_t icsneoc2_mac_addr_entry_t; + #ifdef __cplusplus } #endif diff --git a/test/unit/icsneoc2.cpp b/test/unit/icsneoc2.cpp index f5615af7..534d4c15 100644 --- a/test/unit/icsneoc2.cpp +++ b/test/unit/icsneoc2.cpp @@ -214,7 +214,10 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device) ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_rtc_set(NULL, 0)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_serial_get(NULL, placeholderStr, &placeholderSizeT)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_pcb_serial_get(NULL, &placeholderInteger8, &placeholderSizeT)); - ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_mac_address_get(NULL, &placeholderInteger8, &placeholderSizeT)); + ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_mac_addresses_enumerate(NULL, NULL)); + ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_mac_network_id_get(NULL, NULL)); + ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_mac_address_get(NULL, &placeholderInteger8, &placeholderSizeT)); + ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_mac_addresses_free(NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_supports_tc10(NULL, &placeholderBool)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_tc10_wake_request(NULL, icsneoc2_netid_dwcan_01)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_tc10_sleep_request(NULL, icsneoc2_netid_dwcan_01));