neoVI FIRE 2: MiscIO and EMiscIO Support

pull/32/head
Paul Hollinsky 2021-04-21 10:40:35 -04:00
parent 92589c2ce7
commit bb322ad190
7 changed files with 219 additions and 1 deletions

View File

@ -118,6 +118,26 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
result = msg; result = msg;
return true; return true;
} }
case Network::NetID::Device: {
// These are neoVI network messages
// They come in as CAN but we will handle them in the device rather than
// passing them onto the user.
if(packet->data.size() < 24) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
result = HardwareCANPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
}
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device
result->timestamp *= timestampResolution;
result->network = packet->network;
return true;
}
case Network::NetID::DeviceStatus: { case Network::NetID::DeviceStatus: {
result = std::make_shared<Message>(); result = std::make_shared<Message>();
result->network = packet->network; result->network = packet->network;

View File

@ -470,6 +470,46 @@ optional<bool> Device::getDigitalIO(IO type, size_t number /* = 1 */) {
report(APIEvent::Type::ValueNotYetPresent, APIEvent::Severity::Error); report(APIEvent::Type::ValueNotYetPresent, APIEvent::Severity::Error);
return backupPowerGood; return backupPowerGood;
case IO::Misc: {
bool found = false;
for(const auto& misc : getMiscIO()) {
if(misc.number == number) {
found = misc.supportsDigitalIn;
break;
}
}
if(!found)
break; // ParameterOutOfRange
if(number > miscDigital.size())
break; // ParameterOutOfRange
if(!miscDigital[number - 1].has_value())
report(APIEvent::Type::ValueNotYetPresent, APIEvent::Severity::Error);
return miscDigital[number - 1];
}
case IO::EMisc: {
bool found = false;
for(const auto& misc : getEMiscIO()) {
if(misc.number == number) {
found = misc.supportsDigitalIn;
break;
}
}
if(!found)
break; // ParameterOutOfRange
if(number > miscDigital.size())
break; // ParameterOutOfRange
// If there is ever a device with overlapping misc IOs and emisc IOs,
// you will need to make a new member variable for the emisc IOs.
if(!miscDigital[number - 1].has_value())
report(APIEvent::Type::ValueNotYetPresent, APIEvent::Severity::Error);
return miscDigital[number - 1];
}
}; };
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
@ -522,12 +562,74 @@ bool Device::setDigitalIO(IO type, size_t number, bool value) {
}); });
case IO::BackupPowerGood: case IO::BackupPowerGood:
break; // Read-only, return ParameterOutOfRange break; // Read-only, return ParameterOutOfRange
case IO::Misc:
case IO::EMisc:
break; // Read-only for the moment, return ParameterOutOfRange
}; };
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false; return false;
} }
optional<double> Device::getAnalogIO(IO type, size_t number /* = 1 */) {
if(number == 0) { // Start counting from 1
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
std::lock_guard<std::mutex> lk(ioMutex);
switch(type) {
case IO::EthernetActivation:
case IO::USBHostPower:
case IO::BackupPowerEnabled:
case IO::BackupPowerGood:
break;
case IO::Misc: {
bool found = false;
for(const auto& misc : getMiscIO()) {
if(misc.number == number) {
found = misc.supportsAnalogIn;
break;
}
}
if(!found)
break; // ParameterOutOfRange
if(number > miscAnalog.size())
break; // ParameterOutOfRange
if(!miscAnalog[number - 1].has_value())
report(APIEvent::Type::ValueNotYetPresent, APIEvent::Severity::Error);
return miscAnalog[number - 1];
}
case IO::EMisc: {
bool found = false;
for(const auto& misc : getEMiscIO()) {
if(misc.number == number) {
found = misc.supportsAnalogIn;
break;
}
}
if(!found)
break; // ParameterOutOfRange
if(number > miscAnalog.size())
break; // ParameterOutOfRange
// If there is ever a device with overlapping misc IOs and emisc IOs,
// you will need to make a new member variable for the emisc IOs.
if(!miscAnalog[number - 1].has_value())
report(APIEvent::Type::ValueNotYetPresent, APIEvent::Severity::Error);
return miscAnalog[number - 1];
}
};
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return nullopt;
}
void Device::addExtension(std::shared_ptr<DeviceExtension>&& extension) { void Device::addExtension(std::shared_ptr<DeviceExtension>&& extension) {
std::lock_guard<std::mutex> lk(extensionsLock); std::lock_guard<std::mutex> lk(extensionsLock);
extensions.push_back(extension); extensions.push_back(extension);
@ -552,6 +654,12 @@ void Device::handleInternalMessage(std::shared_ptr<Message> message) {
case Network::NetID::Reset_Status: case Network::NetID::Reset_Status:
latestResetStatus = std::dynamic_pointer_cast<ResetStatusMessage>(message); latestResetStatus = std::dynamic_pointer_cast<ResetStatusMessage>(message);
break; break;
case Network::NetID::Device: {
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(canmsg)
handleNeoVIMessage(std::move(canmsg));
break;
}
case Network::NetID::DeviceStatus: case Network::NetID::DeviceStatus:
// Device Status format is unique per device, so the devices need to decode it themselves // Device Status format is unique per device, so the devices need to decode it themselves
handleDeviceStatus(message); handleDeviceStatus(message);
@ -565,6 +673,27 @@ void Device::handleInternalMessage(std::shared_ptr<Message> message) {
}); });
} }
void Device::handleNeoVIMessage(std::shared_ptr<CANMessage> message) {
switch(message->arbid) {
case 0x103: { // Report Message (neoVI FIRE 2)
if(message->data.size() < 34) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return;
}
uint16_t emisc[2];
memcpy(emisc, message->data.data() + 24, sizeof(emisc));
std::lock_guard<std::mutex> lk(ioMutex);
miscAnalog[0] = (message->data[24] | (uint16_t(message->data[25]) << 8)) * 0.01015511; // In volts now
miscAnalog[1] = (message->data[26] | (uint16_t(message->data[27]) << 8)) * 0.01015511;
miscDigital[0] = message->data[28] & 0x01;
miscDigital[1] = message->data[29] & 0x01;
miscDigital[4] = message->data[30] & 0x01;
miscDigital[5] = message->data[31] & 0x01;
}
}
}
void Device::updateLEDState() { void Device::updateLEDState() {
std::vector<uint8_t> args {(uint8_t) ledState}; std::vector<uint8_t> args {(uint8_t) ledState};
com->sendCommand(Command::UpdateLEDState, args); com->sendCommand(Command::UpdateLEDState, args);

View File

@ -249,6 +249,19 @@ int main() {
ret = device->transmit(ethTxMessage); // This will return false if the device does not support OP (BR) Ethernet 2 ret = device->transmit(ethTxMessage); // This will return false if the device does not support OP (BR) Ethernet 2
std::cout << (ret ? "OK" : "FAIL") << std::endl; std::cout << (ret ? "OK" : "FAIL") << std::endl;
std::vector<icsneo::MiscIO> emisc = device->getEMiscIO();
if(!emisc.empty()) {
std::cout << "\tReading EMisc values..." << std::endl;
for(const auto& io : emisc) {
icsneo::optional<double> val = device->getAnalogIO(icsneo::IO::EMisc, io.number);
std::cout << "\t\tEMISC" << io.number;
if(val.has_value())
std::cout << " - OK (" << val.value() << "V)" << std::endl;
else
std::cout << " - FAIL, it may need to be enabled in neoVI Explorer (" << icsneo::GetLastError() << ")" << std::endl;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::this_thread::sleep_for(std::chrono::milliseconds(50));
// Go offline, stop sending and receiving traffic // Go offline, stop sending and receiving traffic

View File

@ -1,15 +1,30 @@
#ifndef __ICSNEO_IO_H_ #ifndef __ICSNEO_IO_H_
#define __ICSNEO_IO_H_ #define __ICSNEO_IO_H_
typedef struct _neomiscio_t {
size_t number;
bool supportsDigitalIn;
bool supportsDigitalOut;
bool supportsAnalogIn;
#ifdef __cplusplus
_neomiscio_t(size_t n, bool dIn = false, bool dOut = false, bool aIn = false)
: number(n), supportsDigitalIn(dIn), supportsDigitalOut(dOut), supportsAnalogIn(aIn) {}
#endif
} neomiscio_t;
#ifdef __cplusplus #ifdef __cplusplus
namespace icsneo { namespace icsneo {
using MiscIO = neomiscio_t;
enum class IO { enum class IO {
EthernetActivation = 0, // The DoIP activation line, 0 is HiZ and 1 is pulled up to VBAT EthernetActivation = 0, // The DoIP activation line, 0 is HiZ and 1 is pulled up to VBAT
USBHostPower = 1, USBHostPower = 1,
BackupPowerEnabled = 2, // The FIRE 2's backup super capacitor 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) BackupPowerGood = 3, // Whether or not the FIRE 2's backup super capacitor is charged (read only)
Misc = 4, // General purpose IO on the device
EMisc = 5, // Extended general purpose IO on the device
}; };
// Note that the C API does a static cast between this and neoio_t so keep them in sync! // Note that the C API does a static cast between this and neoio_t so keep them in sync!
@ -24,6 +39,8 @@ typedef enum _neoio_t {
ICSNEO_IO_USB_HOST_POWER = (1), ICSNEO_IO_USB_HOST_POWER = (1),
ICSNEO_IO_BACKUP_POWER_EN = (2), ICSNEO_IO_BACKUP_POWER_EN = (2),
ICSNEO_IO_BACKUP_POWER_GOOD = (3), ICSNEO_IO_BACKUP_POWER_GOOD = (3),
ICSNEO_IO_MISC = (4),
ICSNEO_IO_EMISC = (5),
} neoio_t; } neoio_t;
#endif #endif

View File

@ -263,6 +263,7 @@ public:
case NetID::MOST150: case NetID::MOST150:
return Type::MOST; return Type::MOST;
case NetID::RED: case NetID::RED:
case NetID::Device:
case NetID::Reset_Status: case NetID::Reset_Status:
case NetID::DeviceStatus: case NetID::DeviceStatus:
case NetID::FlexRayControl: case NetID::FlexRayControl:
@ -309,7 +310,7 @@ public:
static const char* GetNetIDString(NetID netid) { static const char* GetNetIDString(NetID netid) {
switch(netid) { switch(netid) {
case NetID::Device: case NetID::Device:
return "Device"; return "neoVI";
case NetID::HSCAN: case NetID::HSCAN:
return "HSCAN"; return "HSCAN";
case NetID::MSCAN: case NetID::MSCAN:

View File

@ -107,6 +107,18 @@ public:
*/ */
virtual bool getBackupPowerSupported() const { return false; } virtual bool getBackupPowerSupported() const { return false; }
/**
* Retrieve the information about the misc IOs present on this
* device.
*/
virtual std::vector<MiscIO> getMiscIO() const { return {}; }
/**
* Retrieve the information about the emisc IOs present on this
* device.
*/
virtual std::vector<MiscIO> getEMiscIO() const { return {}; }
/** /**
* Get the value of a digital IO, returning an empty optional if the * 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, * value is not present, the specified IO is not valid for this device,
@ -131,6 +143,16 @@ public:
*/ */
bool setDigitalIO(IO type, bool value) { return setDigitalIO(type, 1, value); } bool setDigitalIO(IO type, bool value) { return setDigitalIO(type, 1, value); }
/**
* Get the value of an analog 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<double> getAnalogIO(IO type, size_t number = 1);
virtual std::vector<std::shared_ptr<FlexRay::Controller>> getFlexRayControllers() const { return {}; } virtual std::vector<std::shared_ptr<FlexRay::Controller>> getFlexRayControllers() const { return {}; }
const device_eventhandler_t& getEventHandler() const { return report; } const device_eventhandler_t& getEventHandler() const { return report; }
@ -150,6 +172,8 @@ protected:
optional<bool> usbHostPowerStatus; optional<bool> usbHostPowerStatus;
optional<bool> backupPowerEnabled; optional<bool> backupPowerEnabled;
optional<bool> backupPowerGood; optional<bool> backupPowerGood;
std::array<optional<bool>, 6> miscDigital;
std::array<optional<double>, 2> miscAnalog;
// START Initialization Functions // START Initialization Functions
Device(neodevice_t neodevice = { 0 }) { Device(neodevice_t neodevice = { 0 }) {
@ -251,6 +275,8 @@ private:
std::vector<Network> supportedTXNetworks; std::vector<Network> supportedTXNetworks;
std::vector<Network> supportedRXNetworks; std::vector<Network> supportedRXNetworks;
void handleNeoVIMessage(std::shared_ptr<CANMessage> message);
enum class LEDState : uint8_t { enum class LEDState : uint8_t {
Offline = 0x04, Offline = 0x04,
CoreMiniRunning = 0x08, // This should override "offline" if the CoreMini is running CoreMiniRunning = 0x08, // This should override "offline" if the CoreMini is running

View File

@ -73,6 +73,18 @@ public:
size_t getEthernetActivationLineCount() const override { return 1; } size_t getEthernetActivationLineCount() const override { return 1; }
size_t getUSBHostPowerCount() const override { return 1; } size_t getUSBHostPowerCount() const override { return 1; }
bool getBackupPowerSupported() const override { return true; } bool getBackupPowerSupported() const override { return true; }
std::vector<MiscIO> getMiscIO() const override {
return {
{5, true, true, false},
{6, true, true, false}
};
}
std::vector<MiscIO> getEMiscIO() const override {
return {
{1, true, true, true},
{2, true, true, true}
};
}
protected: protected:
NeoVIFIRE2(neodevice_t neodevice) : Device(neodevice) { NeoVIFIRE2(neodevice_t neodevice) : Device(neodevice) {