diff --git a/api/icsneoc/icsneoc.cpp b/api/icsneoc/icsneoc.cpp index e40e3c2..a227976 100644 --- a/api/icsneoc/icsneoc.cpp +++ b/api/icsneoc/icsneoc.cpp @@ -608,7 +608,7 @@ bool icsneo_getSupportedDevices(devicetype_t* devices, size_t* count) { return true; } -extern bool DLLExport icsneo_getTimestampResolution(const neodevice_t* device, uint16_t* resolution) { +bool icsneo_getTimestampResolution(const neodevice_t* device, uint16_t* resolution) { if(!icsneo_isValidNeoDevice(device)) return false; @@ -620,3 +620,27 @@ extern bool DLLExport icsneo_getTimestampResolution(const neodevice_t* device, u *resolution = device->device->getTimestampResolution(); return true; } + +bool icsneo_getDigitalIO(const neodevice_t* device, neoio_t type, uint32_t number, uint8_t* value) { + if(!icsneo_isValidNeoDevice(device)) + return false; + + if(value == nullptr) { + EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error); + return false; + } + + const optional val = device->device->getDigitalIO(static_cast(type), number); + if(!val.has_value()) + return false; + + *value = uint8_t(*val); + return true; +} + +bool icsneo_setDigitalIO(const neodevice_t* device, neoio_t type, uint32_t number, uint8_t value) { + if(!icsneo_isValidNeoDevice(device)) + return false; + + return device->device->setDigitalIO(static_cast(type), number, bool(value)); +} diff --git a/api/icsneocpp/event.cpp b/api/icsneocpp/event.cpp index 933b1d5..79b8548 100644 --- a/api/icsneocpp/event.cpp +++ b/api/icsneocpp/event.cpp @@ -69,6 +69,7 @@ static constexpr const char* DEVICE_CURRENTLY_POLLING = "The device is currently static constexpr const char* DEVICE_NOT_CURRENTLY_POLLING = "The device is not currently polling for messages."; static constexpr const char* UNSUPPORTED_TX_NETWORK = "Message network is not a supported TX network."; static constexpr const char* MESSAGE_MAX_LENGTH_EXCEEDED = "The message was too long."; +static constexpr const char* VALUE_NOT_YET_PRESENT = "The value is not yet present."; // Device Errors static constexpr const char* POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!"; @@ -140,6 +141,8 @@ const char* APIEvent::DescriptionForType(Type type) { return UNSUPPORTED_TX_NETWORK; case Type::MessageMaxLengthExceeded: return MESSAGE_MAX_LENGTH_EXCEEDED; + case Type::ValueNotYetPresent: + return VALUE_NOT_YET_PRESENT; // Device Errors case Type::PollingMessageOverflow: diff --git a/api/icsneolegacy/dllhelper/icsneo40DLLAPI.cpp b/api/icsneolegacy/dllhelper/icsneo40DLLAPI.cpp index 8581f5a..e7cf697 100644 --- a/api/icsneolegacy/dllhelper/icsneo40DLLAPI.cpp +++ b/api/icsneolegacy/dllhelper/icsneo40DLLAPI.cpp @@ -45,6 +45,7 @@ SETVCAN412SETTINGS icsneoSetVCAN412Settings; SETBITRATE icsneoSetBitRate; GETDEVICEPARMS icsneoGetDeviceParameters; SETDEVICEPARMS icsneoSetDeviceParameters; +ENABLEDOIPACTIVATIONLINE icsneoEnableDOIPLine; //Error Functions GETLASTAPIERROR icsneoGetLastAPIError; @@ -201,7 +202,7 @@ bool LoadDLLAPI(HINSTANCE &hAPIDLL) icsneoScriptReadAppSignal = (SCRIPTREADAPPSIGNAL) GetProcAddress(hAPIDLL, "icsneoScriptReadAppSignal"); icsneoScriptWriteAppSignal = (SCRIPTWRITEAPPSIGNAL) GetProcAddress(hAPIDLL, "icsneoScriptWriteAppSignal"); - + icsneoEnableDOIPLine = (ENABLEDOIPACTIVATIONLINE)GetProcAddress(hAPIDLL, "icsneoEnableDOIPLine"); if(!icsneoFindNeoDevices || !icsneoOpenNeoDevice || !icsneoClosePort || !icsneoFreeObject || !icsneoTxMessages || !icsneoGetMessages || !icsneoWaitForRxMessagesWithTimeOut || @@ -216,7 +217,7 @@ bool LoadDLLAPI(HINSTANCE &hAPIDLL) !icsneoGetErrorInfo || !icsneoScriptLoad || !icsneoScriptStart || !icsneoScriptStop || !icsneoScriptClear || !icsneoScriptStartFBlock || !icsneoScriptStopFBlock || !icsneoScriptGetFBlockStatus || !icsneoScriptGetScriptStatus || !icsneoScriptReadAppSignal || - !icsneoScriptWriteAppSignal || !icsneoGetDLLVersion) + !icsneoScriptWriteAppSignal || !icsneoGetDLLVersion || !icsneoEnableDOIPLine) { FreeLibrary(hAPIDLL); return false; diff --git a/api/icsneolegacy/dllhelper/icsneo40DLLAPI.h b/api/icsneolegacy/dllhelper/icsneo40DLLAPI.h index 02ceeac..aa2b80c 100644 --- a/api/icsneolegacy/dllhelper/icsneo40DLLAPI.h +++ b/api/icsneolegacy/dllhelper/icsneo40DLLAPI.h @@ -62,6 +62,7 @@ typedef int (__stdcall *SETRADSTAR2SETTINGS)(void * hObject, SRADStar2Settings * typedef int (__stdcall *SETBITRATE)(void * hObject, int BitRate, int NetworkID); typedef int (__stdcall *GETDEVICEPARMS)(void * hObject, char *pParameter, char *pValues, short ValuesLength); typedef int (__stdcall *SETDEVICEPARMS)(void * hObject, char *pParmValue, int *pErrorIndex, int bSaveToEEPROM); +typedef int(__stdcall *ENABLEDOIPACTIVATIONLINE)(void * hObject, bool Val); //Error Functions typedef int (__stdcall *GETLASTAPIERROR)(void * hObject, unsigned long *pErrorNumber); @@ -157,6 +158,7 @@ extern SETVCAN412SETTINGS icsneoSetVCAN412Settings; extern SETBITRATE icsneoSetBitRate; extern GETDEVICEPARMS icsneoGetDeviceParameters; extern SETDEVICEPARMS icsneoSetDeviceParameters; +extern ENABLEDOIPACTIVATIONLINE icsneoEnableDOIPLine; //Error Functions extern GETLASTAPIERROR icsneoGetLastAPIError; diff --git a/api/icsneolegacy/icsneolegacy.cpp b/api/icsneolegacy/icsneolegacy.cpp index 041556c..3380356 100644 --- a/api/icsneolegacy/icsneolegacy.cpp +++ b/api/icsneolegacy/icsneolegacy.cpp @@ -493,6 +493,13 @@ int icsneoGetSerialNumber(void* hObject, unsigned int*iSerialNumber) { return true; } +int icsneoEnableDOIPLine(void* hObject, bool enable) { + if(!icsneoValidateHObject(hObject)) + return false; + neodevice_t* device = (neodevice_t*)hObject; + return icsneo_setDigitalIO(device, ICSNEO_IO_ETH_ACTIVATION, 1, uint8_t(enable)); +} + int icsneoStartSockServer(void* hObject, int iPort) { // TODO Implement return false; diff --git a/communication/decoder.cpp b/communication/decoder.cpp index cf04622..45e78c8 100644 --- a/communication/decoder.cpp +++ b/communication/decoder.cpp @@ -118,6 +118,13 @@ bool Decoder::decode(std::shared_ptr& result, const std::shared_ptr(); + result->network = packet->network; + // Just pass along the data, the device needs to handle this itself + result->data = packet->data; + return true; + } case Network::NetID::FlexRayControl: { auto frResult = std::make_shared(*packet); if(!frResult->decoded) { diff --git a/device/device.cpp b/device/device.cpp index e9533c5..93a630d 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -417,6 +417,106 @@ Network Device::getNetworkByNumber(Network::Type type, size_t index) const { return Network::NetID::Invalid; } +optional Device::getDigitalIO(IO type, size_t number /* = 1 */) { + if(number == 0) { // Start counting from 1 + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return false; + } + + switch(type) { + case IO::EthernetActivation: + if(getEthernetActivationLineCount() < number) + break; // ParameterOutOfRange + assert(number == 1); // If you implement a device with more, you'll need to modify the accessor + + if(!ethActivationStatus.has_value()) + report(APIEvent::Type::ValueNotYetPresent, APIEvent::Severity::Error); + + return ethActivationStatus; + case IO::USBHostPower: + if(getUSBHostPowerCount() < number) + break; // ParameterOutOfRange + assert(number == 1); // If you implement a device with more, you'll need to modify the accessor + + if(!usbHostPowerStatus.has_value()) + report(APIEvent::Type::ValueNotYetPresent, APIEvent::Severity::Error); + + return usbHostPowerStatus; + case IO::BackupPowerEnabled: + if(!getBackupPowerSupported()) + break; // ParameterOutOfRange + assert(number == 1); // If you implement a device with more, you'll need to modify the accessor + + if(!backupPowerEnabled.has_value()) + report(APIEvent::Type::ValueNotYetPresent, APIEvent::Severity::Error); + + return backupPowerEnabled; + case IO::BackupPowerGood: + if(!getBackupPowerSupported()) + break; // ParameterOutOfRange + assert(number == 1); // If you implement a device with more, you'll need to modify the accessor + + if(!backupPowerGood.has_value()) + report(APIEvent::Type::ValueNotYetPresent, APIEvent::Severity::Error); + + return backupPowerGood; + }; + + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return nullopt; +} + +bool Device::setDigitalIO(IO type, size_t number, bool value) { + if(number == 0) { // Start counting from 1 + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return false; + } + + switch(type) { + case IO::EthernetActivation: + if(getEthernetActivationLineCount() < number) + break; // ParameterOutOfRange + assert(number == 1); // If you implement a device with more, you'll need to modify the accessor + + ethActivationStatus = value; + + return com->sendCommand(Command::MiscControl, { + uint8_t(1), uint8_t(value ? 1 : 0), // enetActivateSet, enetActivateValue + uint8_t(0), uint8_t(0), // usbHostPowerSet, usbHostPowerValue + uint8_t(0), uint8_t(0) // backupPowerSet, backupPowerValue + }); + case IO::USBHostPower: + if(getUSBHostPowerCount() < number) + break; // ParameterOutOfRange + assert(number == 1); // If you implement a device with more, you'll need to modify the accessor + + usbHostPowerStatus = value; + + return com->sendCommand(Command::MiscControl, { + uint8_t(0), uint8_t(0), // enetActivateSet, enetActivateValue + uint8_t(1), uint8_t(value ? 1 : 0), // usbHostPowerSet, usbHostPowerValue + uint8_t(0), uint8_t(0) // backupPowerSet, backupPowerValue + }); + case IO::BackupPowerEnabled: + if(!getBackupPowerSupported()) + break; // ParameterOutOfRange + assert(number == 1); // If you implement a device with more, you'll need to modify the accessor + + backupPowerEnabled = value; + + return com->sendCommand(Command::MiscControl, { + uint8_t(0), uint8_t(0), // enetActivateSet, enetActivateValue + uint8_t(0), uint8_t(value ? 1 : 0), // usbHostPowerSet, usbHostPowerValue (set to work around firmware bug) + uint8_t(1), uint8_t(value ? 1 : 0) // backupPowerSet, backupPowerValue + }); + case IO::BackupPowerGood: + break; // Read-only, return ParameterOutOfRange + }; + + report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); + return false; +} + void Device::addExtension(std::shared_ptr&& extension) { std::lock_guard lk(extensionsLock); extensions.push_back(extension); @@ -441,6 +541,10 @@ void Device::handleInternalMessage(std::shared_ptr message) { case Network::NetID::Reset_Status: latestResetStatus = std::dynamic_pointer_cast(message); break; + case Network::NetID::Device_Status: + // Device Status format is unique per device, so the devices need to decode it themselves + handleDeviceStatus(message); + break; default: break; //std::cout << "HandleInternalMessage got a message from " << message->network << " and it was unhandled!" << std::endl; } diff --git a/examples/c/interactive/src/main.c b/examples/c/interactive/src/main.c index d5cb8cd..6a09b89 100644 --- a/examples/c/interactive/src/main.c +++ b/examples/c/interactive/src/main.c @@ -86,6 +86,7 @@ void printMainMenu() { printf("H - Get events\n"); printf("I - Set HS CAN to 250K\n"); printf("J - Set HS CAN to 500K\n"); + printf("L - Set Digital IO\n"); printf("X - Exit\n"); } @@ -235,7 +236,7 @@ int main() { while(true) { printMainMenu(); printf("\n"); - char input = getCharInput(22, 'A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', 'E', 'e', 'F', 'f', 'G', 'g', 'H', 'h', 'I', 'i', 'J', 'j', 'X', 'x'); + char input = getCharInput(24, 'A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', 'E', 'e', 'F', 'f', 'G', 'g', 'H', 'h', 'I', 'i', 'J', 'j', 'L', 'l', 'X', 'x'); printf("\n"); switch(input) { // List current devices @@ -598,6 +599,106 @@ int main() { } } break; + // Set Digital IO + case 'L': + case 'l': + { + // Select a device and get its description + if(numDevices == 0) { + printf("No devices found! Please scan for new devices.\n\n"); + break; + } + selectedDevice = selectDevice(); + + printf("Select from the following:\n"); + + printf("[1] Ethernet (DoIP) Activation Line"); + uint8_t val; + bool haveVal = icsneo_getDigitalIO(selectedDevice, ICSNEO_IO_ETH_ACTIVATION, 1, &val); + if(!haveVal) { + neoevent_t event; + bool got = icsneo_getLastError(&event); + printf(": Unknown (%s)\n", got ? event.description : "No error"); + } else { + if(val) + printf(": Enabled\n"); + else + printf(": Disabled\n"); + } + + printf("[2] USB Host Power"); + haveVal = icsneo_getDigitalIO(selectedDevice, ICSNEO_IO_USB_HOST_POWER, 1, &val); + if(!haveVal) { + neoevent_t event; + bool got = icsneo_getLastError(&event); + printf(": Unknown (%s)\n", got ? event.description : "No error"); + } else { + if(val) + printf(": Enabled\n"); + else + printf(": Disabled\n"); + } + + printf("[3] Backup Power"); + haveVal = icsneo_getDigitalIO(selectedDevice, ICSNEO_IO_BACKUP_POWER_EN, 1, &val); + if(!haveVal) { + neoevent_t event; + bool got = icsneo_getLastError(&event); + printf(": Unknown (%s)\n", got ? event.description : "No error"); + } else { + if(val) + printf(": Enabled "); + else + printf(": Disabled "); + + haveVal = icsneo_getDigitalIO(selectedDevice, ICSNEO_IO_BACKUP_POWER_GOOD, 1, &val); + if(!haveVal) { + neoevent_t event; + bool got = icsneo_getLastError(&event); + printf("with unknown status (%s)\n", got ? event.description : "No error"); + } else { + if(val) + printf("and Charged\n"); + else + printf("and Not Charged\n"); + } + } + + printf("[4] Cancel\n\n"); + char selection = getCharInput(4, '1', '2', '3', '4'); + printf("\n"); + + if(selection == '4') { + printf("Canceling!\n\n"); + break; + } + + printf("[0] Disable\n[1] Enable\n[2] Cancel\n\n"); + char selection2 = getCharInput(3, '0', '1', '2'); + printf("\n"); + + if(selection2 == '2') { + printf("Canceling!\n\n"); + break; + } + + const bool set = selection2 == '1'; + neoio_t type; + switch (selection) + { + case '1': type = ICSNEO_IO_ETH_ACTIVATION; break; + case '2': type = ICSNEO_IO_USB_HOST_POWER; break; + case '3': type = ICSNEO_IO_BACKUP_POWER_EN; break; + }; + if(icsneo_setDigitalIO(selectedDevice, type, 1, set)) { + printf("OK!\n\n"); + } else { + neoevent_t event; + bool got = icsneo_getLastError(&event); + printf("Failure! (%s)\n\n", got ? event.description : "No error"); + } + } + break; // Exit case 'X': case 'x': diff --git a/examples/cpp/interactive/src/InteractiveExample.cpp b/examples/cpp/interactive/src/InteractiveExample.cpp index 630418a..7659237 100644 --- a/examples/cpp/interactive/src/InteractiveExample.cpp +++ b/examples/cpp/interactive/src/InteractiveExample.cpp @@ -42,6 +42,7 @@ void printMainMenu() { std::cout << "I - Set HS CAN to 250K" << std::endl; std::cout << "J - Set LSFT CAN to 250K" << std::endl; std::cout << "K - Add/Remove a message callback" << std::endl; + std::cout << "L - Set Digital IO" << std::endl; std::cout << "X - Exit" << std::endl; } @@ -191,7 +192,7 @@ int main() { while(true) { printMainMenu(); std::cout << std::endl; - char input = getCharInput(std::vector {'A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', 'E', 'e', 'F', 'f', 'G', 'g', 'H', 'h', 'I', 'i', 'J', 'j', 'K', 'k', 'X', 'x'}); + char input = getCharInput(std::vector {'A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', 'E', 'e', 'F', 'f', 'G', 'g', 'H', 'h', 'I', 'i', 'J', 'j', 'K', 'k', 'L', 'l', 'X', 'x'}); std::cout << std::endl; switch(input) { @@ -603,6 +604,123 @@ int main() { } } break; + // Set Digital IO + case 'L': + case 'l': + { + // Select a device and get its description + if(devices.size() == 0) { + std::cout << "No devices found! Please scan for new devices." << std::endl << std::endl; + break; + } + selectedDevice = selectDevice(devices); + + const auto ethAct = selectedDevice->getEthernetActivationLineCount(); + const auto usbHost = selectedDevice->getUSBHostPowerCount(); + const auto backup = selectedDevice->getBackupPowerSupported(); + + if(ethAct == 0 && usbHost == 0 && !backup) { + std::cout << "The selected device has no controllable digital IO." << std::endl << std::endl; + break; + } + + std::vector options = { '1' }; + std::vector names; + std::map< char, std::pair > types; + + std::cout << "Select from the following:" << std::endl; + for(size_t i = 1; i <= ethAct; i++) { + if(i > 1) + options.push_back(options.back() + 1); + names.push_back("Ethernet (DoIP) Activation Line"); + if(ethAct > 1) { + names.back() += ' '; + names.back() += i; + } + std::cout << '[' << options.back() << "] " << names.back(); + const auto val = selectedDevice->getDigitalIO(icsneo::IO::EthernetActivation, i); + types[options.back()] = { icsneo::IO::EthernetActivation, i }; + if(val) { + if(*val) + std::cout << ": Enabled" << std::endl; + else + std::cout << ": Disabled" << std::endl; + } else { + std::cout << ": Unknown (" << icsneo::GetLastError() << ")" << std::endl; + } + } + for(size_t i = 1; i <= usbHost; i++) { + options.push_back(options.back() + 1); + names.push_back("USB Host Power"); + if(usbHost > 1) { + names.back() += ' '; + names.back() += i; + } + std::cout << '[' << options.back() << "] " << names.back(); + const auto val = selectedDevice->getDigitalIO(icsneo::IO::USBHostPower, i); + types[options.back()] = { icsneo::IO::USBHostPower, i }; + if(val) { + if(*val) + std::cout << ": Enabled" << std::endl; + else + std::cout << ": Disabled" << std::endl; + } else { + std::cout << ": Unknown (" << icsneo::GetLastError() << ")" << std::endl; + } + } + if(backup) { + options.push_back(options.back() + 1); + names.push_back("Backup Power"); + std::cout << '[' << options.back() << "] " << names.back() << ": "; + auto val = selectedDevice->getDigitalIO(icsneo::IO::BackupPowerEnabled); + types[options.back()] = { icsneo::IO::BackupPowerEnabled, 1 }; + if(val) { + if(*val) + std::cout << "Enabled"; + else + std::cout << "Disabled"; + + val = selectedDevice->getDigitalIO(icsneo::IO::BackupPowerGood); + if(val) { + if(*val) + std::cout << " and Charged" << std::endl; + else + std::cout << " and Not Charged" << std::endl; + } else { + std::cout << "but the status is unknown (" << icsneo::GetLastError() << ")" << std::endl; + } + } else { + std::cout << "Unknown (" << icsneo::GetLastError() << ")" << std::endl; + } + } + + options.push_back(options.back() + 1); + std::cout << '[' << options.back() << "] Cancel" << std::endl << std::endl; + + char selection = getCharInput(options); + std::cout << std::endl; + + if(selection == options.back()) { + std::cout << "Canceling!" << std::endl << std::endl; + break; + } + + std::cout << "[0] Disable\n[1] Enable\n[2] Cancel" << std::endl << std::endl; + char selection2 = getCharInput({ '0', '1', '2' }); + std::cout << std::endl; + + if(selection2 == '2') { + std::cout << "Canceling!" << std::endl << std::endl; + break; + } + + const bool val = selection2 == '1'; + if(selectedDevice->setDigitalIO(types[selection].first, types[selection].second, val)) + std::cout << "OK!" << std::endl << std::endl; + else + std::cout << "Failure! (" << icsneo::GetLastError() << ")" << std::endl << std::endl; + } + break; // Exit case 'X': case 'x': diff --git a/include/icsneo/api/event.h b/include/icsneo/api/event.h index d3efd2f..a9f5bf0 100644 --- a/include/icsneo/api/event.h +++ b/include/icsneo/api/event.h @@ -46,6 +46,7 @@ public: DeviceNotCurrentlyPolling = 0x1010, UnsupportedTXNetwork = 0x1011, MessageMaxLengthExceeded = 0x1012, + ValueNotYetPresent = 0x1013, // Device Events PollingMessageOverflow = 0x2000, diff --git a/include/icsneo/communication/command.h b/include/icsneo/communication/command.h index 0bc51a2..a45bce7 100644 --- a/include/icsneo/communication/command.h +++ b/include/icsneo/communication/command.h @@ -12,10 +12,11 @@ enum class Command : uint8_t { SetSettings = 0xA4, // Previously known as RED_CMD_SET_BAUD_REQ, follow up with SaveSettings to write to EEPROM //GetSettings = 0xA5, // Previously known as RED_CMD_READ_BAUD_REQ, now unused SaveSettings = 0xA6, + UpdateLEDState = 0xA7, SetDefaultSettings = 0xA8, // Follow up with SaveSettings to write to EEPROM RequestStatusUpdate = 0xBC, ReadSettings = 0xC7, // Previously known as 3G_READ_SETTINGS_EX - UpdateLEDState = 0xA7, + MiscControl = 0xE7, FlexRayControl = 0xF3 }; diff --git a/include/icsneo/communication/io.h b/include/icsneo/communication/io.h new file mode 100644 index 0000000..35ad2ac --- /dev/null +++ b/include/icsneo/communication/io.h @@ -0,0 +1,30 @@ +#ifndef __ICSNEO_IO_H_ +#define __ICSNEO_IO_H_ + +#ifdef __cplusplus + +namespace icsneo { + +enum class IO { + EthernetActivation = 0, // The DoIP activation line, 0 is HiZ and 1 is pulled up to VBAT + USBHostPower = 1, + BackupPowerEnabled = 2, // The FIRE 2's backup super capacitor + BackupPowerGood = 3, // Whether or not the FIRE 2's backup super capacitor is charged (read only) +}; + +// Note that the C API does a static cast between this and neoio_t so keep them in sync! + +} + +#endif // __cplusplus + +#ifdef __ICSNEOC_H_ +typedef enum _neoio_t { + ICSNEO_IO_ETH_ACTIVATION = (0), + ICSNEO_IO_USB_HOST_POWER = (1), + ICSNEO_IO_BACKUP_POWER_EN = (2), + ICSNEO_IO_BACKUP_POWER_GOOD = (3), +} neoio_t; +#endif + +#endif \ No newline at end of file diff --git a/include/icsneo/device/device.h b/include/icsneo/device/device.h index ed757d1..c725e71 100644 --- a/include/icsneo/device/device.h +++ b/include/icsneo/device/device.h @@ -18,10 +18,12 @@ #include "icsneo/communication/packetizer.h" #include "icsneo/communication/encoder.h" #include "icsneo/communication/decoder.h" +#include "icsneo/communication/io.h" #include "icsneo/communication/message/resetstatusmessage.h" #include "icsneo/device/extensions/flexray/controller.h" #include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h" #include "icsneo/third-party/concurrentqueue/concurrentqueue.h" +#include "icsneo/platform/optional.h" namespace icsneo { @@ -86,6 +88,48 @@ public: virtual size_t getNetworkCountByType(Network::Type) const; virtual Network getNetworkByNumber(Network::Type, size_t) const; + /** + * Retrieve the number of Ethernet (DoIP) Activation lines present + * on this device. + */ + virtual size_t getEthernetActivationLineCount() const { return 0; } + + /** + * Retrieve the number of power-controlled USB Host ports present + * on this device. + */ + virtual size_t getUSBHostPowerCount() const { return 0; } + + /** + * Tell whether the current device supports controlling a backup + * power source through the API. + */ + virtual bool getBackupPowerSupported() const { return false; } + + /** + * Get the value of a digital IO, returning an empty optional if the + * value is not present, the specified IO is not valid for this device, + * or if an error occurs. + * + * The index number starts counting at 1 to keep the numbers in sync + * with the numbering on the device, and is set to 1 by default. + */ + optional getDigitalIO(IO type, size_t number = 1); + + /** + * Set a digital IO to either a 1, if value is true, or 0 otherwise. + * + * The index number starts counting at 1 to keep the numbers in sync + * with the numbering on the device. + */ + bool setDigitalIO(IO type, size_t number, bool value); + + /** + * Set the first digital IO of a given type to either a 1, if value + * is true, or 0 otherwise. + */ + bool setDigitalIO(IO type, bool value) { return setDigitalIO(type, 1, value); } + virtual std::vector> getFlexRayControllers() const { return {}; } const device_eventhandler_t& getEventHandler() const { return report; } @@ -99,6 +143,10 @@ protected: int messagePollingCallbackID = 0; int internalHandlerCallbackID = 0; device_eventhandler_t report; + optional ethActivationStatus; + optional usbHostPowerStatus; + optional backupPowerEnabled; + optional backupPowerGood; // START Initialization Functions Device(neodevice_t neodevice = { 0 }) { @@ -185,6 +233,8 @@ protected: void handleInternalMessage(std::shared_ptr message); + virtual void handleDeviceStatus(const std::shared_ptr& message) {} + neodevice_t& getWritableNeoDevice() { return data; } private: diff --git a/include/icsneo/device/idevicesettings.h b/include/icsneo/device/idevicesettings.h index 23d8b91..3a34381 100644 --- a/include/icsneo/device/idevicesettings.h +++ b/include/icsneo/device/idevicesettings.h @@ -47,11 +47,28 @@ enum enum OPEthLinkMode { + OPETH_LINK_INVALID = -1, OPETH_LINK_AUTO = 0, OPETH_LINK_MASTER, OPETH_LINK_SLAVE }; +enum EthLinkSpeed +{ + ETH_SPEED_10 = 0, + ETH_SPEED_100, + ETH_SPEED_1000, +}; + +typedef struct +{ + uint16_t networkId; + uint8_t linkStatus; + uint8_t linkFullDuplex; + uint8_t linkSpeed; // see EthLinkSpeed + int8_t linkMode; // for automotive networks - see OPEthLinkMode +} EthernetNetworkStatus; + typedef struct { uint8_t Mode; @@ -553,6 +570,12 @@ typedef struct _UART_SETTINGS #define UART_SETTINGS_SIZE 16 static_assert(sizeof(UART_SETTINGS) == UART_SETTINGS_SIZE, "UART_SETTINGS is the wrong size!"); +typedef struct { + uint8_t ethernetActivationLineEnabled; + EthernetNetworkStatus ethernetStatus; + uint8_t unused; +} fire2vnet_status_t, flexray_vnetz_status_t; + #pragma pack(pop) #ifdef __cplusplus @@ -592,7 +615,7 @@ public: const uint8_t* offset = (const uint8_t*)getCANSettingsFor(net); if(offset == nullptr) return nullptr; - return static_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); + return reinterpret_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); } virtual const CANFD_SETTINGS* getCANFDSettingsFor(Network net) const { (void)net; return nullptr; } @@ -602,7 +625,7 @@ public: const uint8_t* offset = (const uint8_t*)getCANFDSettingsFor(net); if(offset == nullptr) return nullptr; - return static_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); + return reinterpret_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); } virtual const CAN_SETTINGS* getLSFTCANSettingsFor(Network net) const { (void)net; return nullptr; } @@ -612,7 +635,7 @@ public: const uint8_t* offset = (const uint8_t*)getLSFTCANSettingsFor(net); if(offset == nullptr) return nullptr; - return static_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); + return reinterpret_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); } virtual const SWCAN_SETTINGS* getSWCANSettingsFor(Network net) const { (void)net; return nullptr; } @@ -622,13 +645,13 @@ public: const uint8_t* offset = (const uint8_t*)getSWCANSettingsFor(net); if(offset == nullptr) return nullptr; - return static_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); + return reinterpret_cast((void*)(settings.data() + (offset - settingsInDeviceRAM.data()))); } const void* getRawStructurePointer() const { return settingsInDeviceRAM.data(); } void* getMutableRawStructurePointer() { return settings.data(); } - template const T* getStructurePointer() const { return static_cast(getRawStructurePointer()); } - template T* getMutableStructurePointer() { return static_cast(getMutableRawStructurePointer()); } + template const T* getStructurePointer() const { return reinterpret_cast(getRawStructurePointer()); } + template T* getMutableStructurePointer() { return reinterpret_cast(getMutableRawStructurePointer()); } template T getStructure() const { return *getStructurePointer(); } template bool applyStructure(const T& newStructure); diff --git a/include/icsneo/device/tree/neovifire2/neovifire2.h b/include/icsneo/device/tree/neovifire2/neovifire2.h index f10fa7a..819fcb1 100644 --- a/include/icsneo/device/tree/neovifire2/neovifire2.h +++ b/include/icsneo/device/tree/neovifire2/neovifire2.h @@ -6,6 +6,7 @@ #include "icsneo/device/device.h" #include "icsneo/device/devicetype.h" #include "icsneo/platform/ftdi.h" +#include "icsneo/device/tree/neovifire2/neovifire2settings.h" namespace icsneo { @@ -46,6 +47,10 @@ public: return supportedNetworks; } + size_t getEthernetActivationLineCount() const override { return 1; } + size_t getUSBHostPowerCount() const override { return 1; } + bool getBackupPowerSupported() const override { return true; } + protected: NeoVIFIRE2(neodevice_t neodevice) : Device(neodevice) { getWritableNeoDevice().type = DEVICE_TYPE; @@ -63,6 +68,16 @@ protected: // The supported TX networks are the same as the supported RX networks for this device virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } + + void handleDeviceStatus(const std::shared_ptr& message) override { + if(!message || message->data.size() < sizeof(neovifire2_status_t)) + return; + const neovifire2_status_t* status = reinterpret_cast(message->data.data()); + backupPowerEnabled = status->backupPowerEnabled; + backupPowerGood = status->backupPowerGood; + ethActivationStatus = status->ethernetActivationLineEnabled; + usbHostPowerStatus = status->usbHostPowerEnabled; + } }; } diff --git a/include/icsneo/device/tree/neovifire2/neovifire2eth.h b/include/icsneo/device/tree/neovifire2/neovifire2eth.h index 57d100c..ca980c4 100644 --- a/include/icsneo/device/tree/neovifire2/neovifire2eth.h +++ b/include/icsneo/device/tree/neovifire2/neovifire2eth.h @@ -5,7 +5,6 @@ #include "icsneo/device/tree/neovifire2/neovifire2.h" #include "icsneo/platform/pcap.h" -#include "icsneo/device/tree/neovifire2/neovifire2settings.h" #include namespace icsneo { diff --git a/include/icsneo/device/tree/neovifire2/neovifire2settings.h b/include/icsneo/device/tree/neovifire2/neovifire2settings.h index fd7271f..0e028bd 100644 --- a/include/icsneo/device/tree/neovifire2/neovifire2settings.h +++ b/include/icsneo/device/tree/neovifire2/neovifire2settings.h @@ -106,6 +106,14 @@ typedef struct { TIMESYNC_ICSHARDWARE_SETTINGS timeSync; DISK_SETTINGS disk; } neovifire2_settings_t; + +typedef struct { + uint8_t backupPowerGood; + uint8_t backupPowerEnabled; + uint8_t usbHostPowerEnabled; + uint8_t ethernetActivationLineEnabled; + EthernetNetworkStatus ethernetStatus; +} neovifire2_status_t; #pragma pack(pop) #ifdef __cplusplus diff --git a/include/icsneo/device/tree/neovifire2/neovifire2usb.h b/include/icsneo/device/tree/neovifire2/neovifire2usb.h index 4eac9d6..04e73f7 100644 --- a/include/icsneo/device/tree/neovifire2/neovifire2usb.h +++ b/include/icsneo/device/tree/neovifire2/neovifire2usb.h @@ -5,7 +5,6 @@ #include "icsneo/device/tree/neovifire2/neovifire2.h" #include "icsneo/platform/ftdi.h" -#include "icsneo/device/tree/neovifire2/neovifire2settings.h" namespace icsneo { diff --git a/include/icsneo/device/tree/plasion/plasion.h b/include/icsneo/device/tree/plasion/plasion.h index f28df3d..c1d5926 100644 --- a/include/icsneo/device/tree/plasion/plasion.h +++ b/include/icsneo/device/tree/plasion/plasion.h @@ -41,6 +41,9 @@ public: return supportedNetworks; } + // Until VNET support is added, assume we have one FIRE 2 VNET or FlexRay VNETZ as the main + size_t getEthernetActivationLineCount() const override { return 1; } + protected: virtual std::shared_ptr makeCommunication( std::unique_ptr transport, @@ -92,6 +95,13 @@ protected: return ret; } + void handleDeviceStatus(const std::shared_ptr& message) override { + if(!message || message->data.size() < sizeof(fire2vnet_status_t)) + return; + const fire2vnet_status_t* status = reinterpret_cast(message->data.data()); + ethActivationStatus = status->ethernetActivationLineEnabled; + } + public: Plasion(neodevice_t neodevice) : Device(neodevice) {} }; diff --git a/include/icsneo/device/tree/radgalaxy/radgalaxy.h b/include/icsneo/device/tree/radgalaxy/radgalaxy.h index 966bcdc..6a43b76 100644 --- a/include/icsneo/device/tree/radgalaxy/radgalaxy.h +++ b/include/icsneo/device/tree/radgalaxy/radgalaxy.h @@ -91,6 +91,8 @@ public: productId = PRODUCT_ID; } + size_t getEthernetActivationLineCount() const override { return 1; } + protected: void setupPacketizer(Packetizer& packetizer) override { Device::setupPacketizer(packetizer); @@ -115,6 +117,13 @@ protected: // The supported TX networks are the same as the supported RX networks for this device void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } + + void handleDeviceStatus(const std::shared_ptr& message) override { + if(!message || message->data.size() < sizeof(radgalaxy_status_t)) + return; + const radgalaxy_status_t* status = reinterpret_cast(message->data.data()); + ethActivationStatus = status->ethernetActivationLineEnabled; + } }; } diff --git a/include/icsneo/device/tree/radgalaxy/radgalaxysettings.h b/include/icsneo/device/tree/radgalaxy/radgalaxysettings.h index 980c079..7643147 100644 --- a/include/icsneo/device/tree/radgalaxy/radgalaxysettings.h +++ b/include/icsneo/device/tree/radgalaxy/radgalaxysettings.h @@ -87,6 +87,11 @@ typedef struct { DISK_SETTINGS disk; LOGGER_SETTINGS logger; } radgalaxy_settings_t; + +typedef struct { + uint8_t unused[3]; + uint8_t ethernetActivationLineEnabled; +} radgalaxy_status_t; #pragma pack(pop) #ifdef __cplusplus diff --git a/include/icsneo/device/tree/radgigalog/radgigalog.h b/include/icsneo/device/tree/radgigalog/radgigalog.h index 5d5abd8..b8eeb02 100644 --- a/include/icsneo/device/tree/radgigalog/radgigalog.h +++ b/include/icsneo/device/tree/radgigalog/radgigalog.h @@ -14,6 +14,8 @@ public: static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADGigalog; static constexpr const char* SERIAL_START = "GL"; + size_t getEthernetActivationLineCount() const override { return 1; } + protected: RADGigalog(neodevice_t neodevice) : Device(neodevice) { getWritableNeoDevice().type = DEVICE_TYPE; @@ -74,6 +76,13 @@ protected: }; txNetworks.insert(txNetworks.end(), supportedTxNetworks.begin(), supportedTxNetworks.end()); } + + void handleDeviceStatus(const std::shared_ptr& message) override { + if(!message || message->data.size() < sizeof(radgigalog_status_t)) + return; + const radgigalog_status_t* status = reinterpret_cast(message->data.data()); + ethActivationStatus = status->ethernetActivationLineEnabled; + } }; } diff --git a/include/icsneo/device/tree/radgigalog/radgigalogsettings.h b/include/icsneo/device/tree/radgigalog/radgigalogsettings.h index 030e9ec..d26eb5c 100644 --- a/include/icsneo/device/tree/radgigalog/radgigalogsettings.h +++ b/include/icsneo/device/tree/radgigalog/radgigalogsettings.h @@ -86,6 +86,11 @@ typedef struct { uint16_t network_enables_4; RAD_REPORTING_SETTINGS reporting; } radgigalog_settings_t; + +typedef struct { + uint8_t unused[3]; + uint8_t ethernetActivationLineEnabled; +} radgigalog_status_t; #pragma pack(pop) #ifdef __cplusplus diff --git a/include/icsneo/device/tree/radgigastar/radgigastar.h b/include/icsneo/device/tree/radgigastar/radgigastar.h index c0aa250..e85d277 100644 --- a/include/icsneo/device/tree/radgigastar/radgigastar.h +++ b/include/icsneo/device/tree/radgigastar/radgigastar.h @@ -14,6 +14,8 @@ public: static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADGigastar; static constexpr const char* SERIAL_START = "GS"; + size_t getEthernetActivationLineCount() const override { return 1; } + protected: RADGigastar(neodevice_t neodevice) : Device(neodevice) { getWritableNeoDevice().type = DEVICE_TYPE; @@ -78,6 +80,13 @@ protected: }; txNetworks.insert(txNetworks.end(), supportedTxNetworks.begin(), supportedTxNetworks.end()); } + + void handleDeviceStatus(const std::shared_ptr& message) override { + if(!message || message->data.size() < sizeof(radgigastar_status_t)) + return; + const radgigastar_status_t* status = reinterpret_cast(message->data.data()); + ethActivationStatus = status->ethernetActivationLineEnabled; + } }; } diff --git a/include/icsneo/device/tree/radgigastar/radgigastarsettings.h b/include/icsneo/device/tree/radgigastar/radgigastarsettings.h index c1aed9d..ec3b59e 100644 --- a/include/icsneo/device/tree/radgigastar/radgigastarsettings.h +++ b/include/icsneo/device/tree/radgigastar/radgigastarsettings.h @@ -135,6 +135,11 @@ public: } }; +typedef struct { + uint8_t unused[3]; + uint8_t ethernetActivationLineEnabled; +} radgigastar_status_t; + } #endif // __cplusplus diff --git a/include/icsneo/device/tree/valuecan4/settings/valuecan4settings.h b/include/icsneo/device/tree/valuecan4/settings/valuecan4settings.h index 301d84b..baa0f98 100644 --- a/include/icsneo/device/tree/valuecan4/settings/valuecan4settings.h +++ b/include/icsneo/device/tree/valuecan4/settings/valuecan4settings.h @@ -76,6 +76,12 @@ typedef struct { uint16_t pwr_man_timeout; } valuecan4_4_2el_settings_t, valuecan4_4_settings_t, valuecan4_2el_settings_t; +typedef struct +{ + uint8_t ethernetActivationLineEnabled; + uint8_t unused; +} valuecan4_4_2el_status_t, valuecan4_4_status_t, valuecan4_2el_status_t; + typedef struct { CAN_SETTINGS can1; CANFD_SETTINGS canfd1; diff --git a/include/icsneo/device/tree/valuecan4/valuecan4-2el.h b/include/icsneo/device/tree/valuecan4/valuecan4-2el.h index 126636f..94fb0a1 100644 --- a/include/icsneo/device/tree/valuecan4/valuecan4-2el.h +++ b/include/icsneo/device/tree/valuecan4/valuecan4-2el.h @@ -19,6 +19,15 @@ protected: ValueCAN4_2EL(neodevice_t neodevice) : ValueCAN4(neodevice) { getWritableNeoDevice().type = DEVICE_TYPE; } + + size_t getEthernetActivationLineCount() const override { return 1; } + + void handleDeviceStatus(const std::shared_ptr& message) override { + if(!message || message->data.size() < sizeof(valuecan4_2el_status_t)) + return; + const valuecan4_2el_status_t* status = reinterpret_cast(message->data.data()); + ethActivationStatus = status->ethernetActivationLineEnabled; + } }; } diff --git a/include/icsneo/icsneoc.h b/include/icsneo/icsneoc.h index 513c48b..c58bf00 100644 --- a/include/icsneo/icsneoc.h +++ b/include/icsneo/icsneoc.h @@ -8,6 +8,7 @@ #include "icsneo/communication/message/neomessage.h" // For neomessage_t and friends #include "icsneo/platform/dynamiclib.h" // Dynamic library loading and exporting #include "icsneo/communication/network.h" // Network type and netID defines +#include "icsneo/communication/io.h" // IO enum defines #include "icsneo/api/version.h" // For version info #include "icsneo/api/event.h" // For event and error info @@ -713,8 +714,29 @@ extern bool DLLExport icsneo_getSupportedDevices(devicetype_t* devices, size_t* */ extern bool DLLExport icsneo_getTimestampResolution(const neodevice_t* device, uint16_t* resolution); +/** + * \brief Get the value of a digital IO for the given device + * \param[in] device A pointer to the neodevice_t structure specifying the device to operate on. + * \param[in] type The IO type + * \param[in] number The index within the IO type, starting from 1 + * \param[out] value A pointer to the uint8_t which will store the value of the IO port, if successful + * \returns True if the value is read successfully + * + * These values are often not populated if the device is not "online". + */ +extern bool DLLExport icsneo_getDigitalIO(const neodevice_t* device, neoio_t type, uint32_t number, uint8_t* value); - +/** + * \brief Get the value of a digital IO for the given device + * \param[in] device A pointer to the neodevice_t structure specifying the device to operate on. + * \param[in] type The IO type + * \param[in] number The index within the IO type, starting from 1 + * \param[in] value The value which will be written to the IO + * \returns True if the parameters and connection state are correct to submit the request to the device + * + * Note that this function is not synchronous with the device confirming the change. + */ +extern bool DLLExport icsneo_setDigitalIO(const neodevice_t* device, neoio_t type, uint32_t number, uint8_t value); #ifdef __cplusplus } // extern "C" @@ -860,6 +882,18 @@ fn_icsneo_setEventLimit icsneo_setEventLimit; typedef size_t(*fn_icsneo_getEventLimit)(void); fn_icsneo_getEventLimit icsneo_getEventLimit; +typedef bool(*fn_icsneo_getSupportedDevices)(devicetype_t* devices, size_t* count); +fn_icsneo_getSupportedDevices icsneo_getSupportedDevices; + +typedef bool(*fn_icsneo_getTimestampResolution)(const neodevice_t* device, uint16_t* resolution); +fn_icsneo_getTimestampResolution icsneo_getTimestampResolution; + +typedef bool(*fn_icsneo_getDigitalIO)(const neodevice_t* device, neoio_t type, uint32_t number, uint8_t* value); +fn_icsneo_getDigitalIO icsneo_getDigitalIO; + +typedef bool(*fn_icsneo_setDigitalIO)(const neodevice_t* device, neoio_t type, uint32_t number, uint8_t value); +fn_icsneo_setDigitalIO icsneo_setDigitalIO; + #define ICSNEO_IMPORT(func) func = (fn_##func)icsneo_dynamicLibraryGetFunction(icsneo_libraryHandle, #func) #define ICSNEO_IMPORTASSERT(func) if((ICSNEO_IMPORT(func)) == NULL) return 3 void* icsneo_libraryHandle = NULL; @@ -920,6 +954,10 @@ int icsneo_init() { ICSNEO_IMPORTASSERT(icsneo_discardDeviceEvents); ICSNEO_IMPORTASSERT(icsneo_setEventLimit); ICSNEO_IMPORTASSERT(icsneo_getEventLimit); + ICSNEO_IMPORTASSERT(icsneo_getSupportedDevices); + ICSNEO_IMPORTASSERT(icsneo_getTimestampResolution); + ICSNEO_IMPORTASSERT(icsneo_getDigitalIO); + ICSNEO_IMPORTASSERT(icsneo_setDigitalIO); icsneo_initialized = true; return 0;