diff --git a/CMakeLists.txt b/CMakeLists.txt index 0220e40..35ec376 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ set(COMMON_SRC communication/multichannelcommunication.cpp communication/communication.cpp communication/icommunication.cpp + device/idevicesettings.cpp device/devicefinder.cpp device/device.cpp ) diff --git a/communication/communication.cpp b/communication/communication.cpp index 5e0392c..1a6396e 100644 --- a/communication/communication.cpp +++ b/communication/communication.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "communication/include/messagedecoder.h" #include "communication/include/packetizer.h" @@ -67,10 +69,34 @@ bool Communication::sendCommand(Communication::Command cmd, std::vector bytes.push_back((uint8_t)cmd); for(auto& b : arguments) bytes.push_back(b); - bytes.insert(bytes.begin(), 0xB | ((uint8_t)bytes.size() << 4)); + bytes.insert(bytes.begin(), (uint8_t)Network::NetID::Main51 | ((uint8_t)bytes.size() << 4)); return sendPacket(bytes); } +bool Communication::getSettingsSync(std::vector& data, std::chrono::milliseconds timeout) { + sendCommand(Command::GetSettings); + std::shared_ptr msg = waitForMessageSync(MessageFilter(Network::NetID::RED_READ_BAUD_SETTINGS), timeout); + if(!msg) + return false; + + data = std::move(msg->data); + return true; +} + +bool Communication::getSerialNumberSync(std::string& serial, std::chrono::milliseconds timeout) { + sendCommand(Command::RequestSerialNumber); + std::shared_ptr msg = waitForMessageSync(MessageFilter(Network::NetID::Main51), timeout); + if(!msg) + return false; + + std::cout << "Got " << msg->data.size() << " bytes" << std::endl; + for(size_t i = 0; i < msg->data.size(); i++) { + std::cout << std::hex << (int)msg->data[i] << ' ' << std::dec; + if(i % 16 == 15) + std::cout << std::endl; + } +} + int Communication::addMessageCallback(const MessageCallback& cb) { messageCallbacks.insert(std::make_pair(messageCallbackIDCounter, cb)); return messageCallbackIDCounter++; @@ -85,6 +111,29 @@ bool Communication::removeMessageCallback(int id) { } } +std::shared_ptr Communication::waitForMessageSync(MessageFilter f, std::chrono::milliseconds timeout) { + std::mutex m; + std::condition_variable cv; + std::shared_ptr returnedMessage; + int cb = addMessageCallback(MessageCallback([&m, &returnedMessage, &cv](std::shared_ptr message) { + { + std::lock_guard lk(m); + returnedMessage = message; + } + cv.notify_one(); + }, f)); + + // We have now added the callback, wait for it to return from the other thread + std::unique_lock lk(m); + cv.wait_for(lk, timeout, [&returnedMessage]{ return !!returnedMessage; }); // `!!shared_ptr` checks if the ptr has a value + + // We don't actually check that we got a message, because either way we want to remove the callback (since it should only happen once) + removeMessageCallback(cb); + + // Then we either will return the message we got or we will return the empty shared_ptr, caller responsible for checking + return returnedMessage; +} + void Communication::readTask() { std::vector readBytes; Packetizer packetizer; diff --git a/communication/include/communication.h b/communication/include/communication.h index 92b5fad..fcf9336 100644 --- a/communication/include/communication.h +++ b/communication/include/communication.h @@ -30,13 +30,19 @@ public: enum class Command : uint8_t { EnableNetworkCommunication = 0x07, - RequestSerialNumber = 0xA1 + RequestSerialNumber = 0xA1, + 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 + SaveSettings = 0xA6 }; virtual bool sendCommand(Command cmd, bool boolean) { return sendCommand(cmd, std::vector({ (uint8_t)boolean })); } virtual bool sendCommand(Command cmd, std::vector arguments = {}); + bool getSettingsSync(std::vector& data, std::chrono::milliseconds timeout = std::chrono::milliseconds(10)); + bool getSerialNumberSync(std::string& serial, std::chrono::milliseconds timeout = std::chrono::milliseconds(10)); int addMessageCallback(const MessageCallback& cb); bool removeMessageCallback(int id); + std::shared_ptr waitForMessageSync(MessageFilter f = MessageFilter(), std::chrono::milliseconds timeout = std::chrono::milliseconds(10)); void setAlign16Bit(bool enable) { align16bit = enable; } diff --git a/communication/include/network.h b/communication/include/network.h index 059fa01..9f7c192 100644 --- a/communication/include/network.h +++ b/communication/include/network.h @@ -29,6 +29,32 @@ public: OP_Ethernet1 = 17, OP_Ethernet2 = 18, OP_Ethernet3 = 19, + + // START Device Command Returns + // When we send a command, the device returns on one of these, depending on command + RED_EXT_MEMORYREAD = 20, + RED_INT_MEMORYREAD = 21, + RED_DFLASH_READ = 22, + RED_SDCARD_READ = 23, + CAN_ERRBITS = 24, + RED_DFLASH_WRITE_DONE = 25, + RED_WAVE_CAN1_LOGICAL = 26, + RED_WAVE_CAN2_LOGICAL = 27, + RED_WAVE_LIN1_LOGICAL = 28, + RED_WAVE_LIN2_LOGICAL = 29, + RED_WAVE_LIN1_ANALOG = 30, + RED_WAVE_LIN2_ANALOG = 31, + RED_WAVE_MISC_ANALOG = 32, + RED_WAVE_MISCDIO2_LOGICAL = 33, + RED_NETWORK_COM_ENABLE_EX = 34, + RED_NEOVI_NETWORK = 35, + RED_READ_BAUD_SETTINGS = 36, + RED_OLDFORMAT = 37, + RED_SCOPE_CAPTURE = 38, + RED_HARDWARE_EXCEP = 39, + RED_GET_RTC = 40, + // END Device Command Returns + ISO3 = 41, HSCAN2 = 42, HSCAN3 = 44, @@ -38,8 +64,8 @@ public: LIN2 = 48, LIN3 = 49, LIN4 = 50, - MOST = 51, - Red_App_Error = 52, + // MOST = 51, Old and unused + RED_App_Error = 52, CGI = 53, Reset_Status = 54, FB_Status = 55, @@ -143,7 +169,6 @@ public: case NetID::FlexRay2a: case NetID::FlexRay2b: return Type::FlexRay; - case NetID::MOST: case NetID::MOST25: case NetID::MOST50: case NetID::MOST150: @@ -196,6 +221,48 @@ public: return "Ethernet 2"; case NetID::OP_Ethernet3: return "Ethernet 3"; + case NetID::RED_EXT_MEMORYREAD: + return "RED_EXT_MEMORYREAD"; + case NetID::RED_INT_MEMORYREAD: + return "RED_INT_MEMORYREAD"; + case NetID::RED_DFLASH_READ: + return "RED_DFLASH_READ"; + case NetID::RED_SDCARD_READ: + return "RED_SDCARD_READ"; + case NetID::CAN_ERRBITS: + return "CAN_ERRBITS"; + case NetID::RED_DFLASH_WRITE_DONE: + return "RED_DFLASH_WRITE_DONE"; + case NetID::RED_WAVE_CAN1_LOGICAL: + return "RED_WAVE_CAN1_LOGICAL"; + case NetID::RED_WAVE_CAN2_LOGICAL: + return "RED_WAVE_CAN2_LOGICAL"; + case NetID::RED_WAVE_LIN1_LOGICAL: + return "RED_WAVE_LIN1_LOGICAL"; + case NetID::RED_WAVE_LIN2_LOGICAL: + return "RED_WAVE_LIN2_LOGICAL"; + case NetID::RED_WAVE_LIN1_ANALOG: + return "RED_WAVE_LIN1_ANALOG"; + case NetID::RED_WAVE_LIN2_ANALOG: + return "RED_WAVE_LIN2_ANALOG"; + case NetID::RED_WAVE_MISC_ANALOG: + return "RED_WAVE_MISC_ANALOG"; + case NetID::RED_WAVE_MISCDIO2_LOGICAL: + return "RED_WAVE_MISCDIO2_LOGICAL"; + case NetID::RED_NETWORK_COM_ENABLE_EX: + return "RED_NETWORK_COM_ENABLE_EX"; + case NetID::RED_NEOVI_NETWORK: + return "RED_NEOVI_NETWORK"; + case NetID::RED_READ_BAUD_SETTINGS: + return "RED_READ_BAUD_SETTINGS"; + case NetID::RED_OLDFORMAT: + return "RED_OLDFORMAT"; + case NetID::RED_SCOPE_CAPTURE: + return "RED_SCOPE_CAPTURE"; + case NetID::RED_HARDWARE_EXCEP: + return "RED_HARDWARE_EXCEP"; + case NetID::RED_GET_RTC: + return "RED_GET_RTC"; case NetID::ISO3: return "ISO 3"; case NetID::HSCAN2: @@ -214,10 +281,8 @@ public: return "LIN 3"; case NetID::LIN4: return "LIN 4"; - case NetID::MOST: - return "MOST"; - case NetID::Red_App_Error: - return "Red App Error"; + case NetID::RED_App_Error: + return "App Error"; case NetID::CGI: return "CGI"; case NetID::Reset_Status: diff --git a/device/device.cpp b/device/device.cpp index dbc0d04..6788b10 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -133,11 +133,16 @@ bool Device::close() { } bool Device::goOnline() { + std::string serial; + while(!com->getSerialNumberSync(serial, std::chrono::milliseconds(500))) { + std::cout << "Serial number not here yet" << std::endl; + } + if(!com->sendCommand(Communication::Command::EnableNetworkCommunication, true)) return false; - - if(!com->sendCommand(Communication::Command::RequestSerialNumber)) - return false; + + // if(!com->sendCommand(Communication::Command::RequestSerialNumber)) + // return false; return online = true; } diff --git a/device/idevicesettings.cpp b/device/idevicesettings.cpp new file mode 100644 index 0000000..0cff1c9 --- /dev/null +++ b/device/idevicesettings.cpp @@ -0,0 +1,76 @@ +#include "device/include/idevicesettings.h" + +using namespace icsneo; + +uint16_t IDeviceSettings::CalculateGSChecksum(const std::vector& settings) { + uint16_t gs_crc = 0; + const uint16_t* p = (const uint16_t*)settings.data(); + size_t words = settings.size(); + if(words % 2 == 1) + return 0xFFFF; // Somehow settings is not word aligned + words /= 2; + + while(words--) { + uint16_t temp = *p; + + for (int i = 0; i < 16; i++) { + bool iBit = temp & 1; + + int iCrcNxt; + //CRCNXT = NXTBIT EXOR CRC_RG(15); + if (gs_crc & (1 << 15)) + iCrcNxt = iBit ^ 1; + else + iCrcNxt = iBit; + iCrcNxt = iCrcNxt & 0x01; + + + // CRC_RG(15:1) = CRC_RG(14:0); // shift left by + gs_crc = gs_crc << 1; + gs_crc = gs_crc & 0xFFFE;// clear first bit + + if (iCrcNxt)//CRC_RG(14:0) = CRC_RG(14:0) EXOR (4599hex); + gs_crc = gs_crc ^ 0xa001; + + temp >>= 1; + } + + p++; + } + return gs_crc; +} + +void IDeviceSettings::refresh() { + std::vector rxSettings; + bool ret = com->getSettingsSync(rxSettings); + if(ret) { + if(rxSettings.size() < 6) // We need to at least have the header of GLOBAL_SETTINGS + return; + + constexpr size_t gs_size = 3 * sizeof(uint16_t); + size_t rxLen = rxSettings.size() - gs_size; + + uint16_t gs_version = rxSettings[0] | (rxSettings[1] << 8); + uint16_t gs_len = rxSettings[2] | (rxSettings[3] << 8); + uint16_t gs_chksum = rxSettings[4] | (rxSettings[5] << 8); + rxSettings.erase(rxSettings.begin(), rxSettings.begin() + gs_size); + + if(gs_version != 5) { + std::cout << "gs_version was " << gs_version << " instead of 5.\nPlease update your firmware." << std::endl; + return; + } + + if(rxLen != gs_len) { + std::cout << "rxLen was " << rxLen << " and gs_len was " << gs_len << " while reading settings" << std::endl; + return; + } + + if(gs_chksum != CalculateGSChecksum(rxSettings)) { + std::cout << "Checksum mismatch while reading settings" << std::endl; + return; + } + + settings = std::move(rxSettings); + settingsLoaded = true; + } +} \ No newline at end of file diff --git a/device/include/device.h b/device/include/device.h index 890fa63..ad14f39 100644 --- a/device/include/device.h +++ b/device/include/device.h @@ -5,6 +5,7 @@ #include #include #include "device/include/neodevice.h" +#include "device/include/idevicesettings.h" #include "communication/include/communication.h" #include "third-party/concurrentqueue/concurrentqueue.h" @@ -50,6 +51,8 @@ public: enforcePollingMessageLimit(); } + std::shared_ptr settings; + protected: uint16_t productId = 0; bool online = false; @@ -65,7 +68,7 @@ protected: private: neodevice_t data; - + size_t pollingMessageLimit = 20000; moodycamel::ConcurrentQueue> pollingContainer; void enforcePollingMessageLimit(); diff --git a/device/include/idevicesettings.h b/device/include/idevicesettings.h new file mode 100644 index 0000000..0c64627 --- /dev/null +++ b/device/include/idevicesettings.h @@ -0,0 +1,227 @@ +#ifndef __IDEVICESETTINGS_H_ +#define __IDEVICESETTINGS_H_ + +#include + +#ifdef __cplusplus +#include "communication/include/communication.h" +#include + +namespace icsneo { + +class IDeviceSettings { +public: + static uint16_t CalculateGSChecksum(const std::vector& settings); + + IDeviceSettings(std::shared_ptr com) : com(com) { + refresh(); + } + virtual void refresh(); + virtual void commit() = 0; + virtual void* getStructure() { return settings.data(); } + virtual bool setBaudrate(int baud) = 0; +protected: + bool settingsLoaded = false; + std::vector settings; + std::shared_ptr com; +}; + +#endif + +/* SetBaudrate in CAN_SETTINGS */ +enum +{ + AUTO, + USE_TQ +}; + +/* Baudrate in CAN_SETTINGS/CANFD_SETTINGS */ +enum +{ + BPS20, + BPS33, + BPS50, + BPS62, + BPS83, + BPS100, + BPS125, + BPS250, + BPS500, + BPS800, + BPS1000, + BPS666, + BPS2000, + BPS4000, + CAN_BPS5000, + CAN_BPS6667, + CAN_BPS8000, + CAN_BPS10000, +}; + +/* Mode in CAN_SETTINGS */ +enum +{ + NORMAL = 0, + DISABLE = 1, + LOOPBACK = 2, + LISTEN_ONLY = 3, + LISTEN_ALL = 7 +}; + +typedef struct +{ + uint8_t Mode; + uint8_t SetBaudrate; + uint8_t Baudrate; + uint8_t transceiver_mode; + uint8_t TqSeg1; + uint8_t TqSeg2; + uint8_t TqProp; + uint8_t TqSync; + uint16_t BRP; + uint8_t auto_baud; + uint8_t innerFrameDelay25us; +} CAN_SETTINGS; +#define CAN_SETTINGS_SIZE 12 + +/* FDMode in CANFD_SETTINGS */ +enum +{ + NO_CANFD, + CANFD_ENABLED, + CANFD_BRS_ENABLED, + CANFD_ENABLED_ISO, + CANFD_BRS_ENABLED_ISO +}; + +typedef struct _CANFD_SETTINGS +{ + uint8_t FDMode; /* mode, secondary baudrate for canfd */ + uint8_t FDBaudrate; + uint8_t FDTqSeg1; + uint8_t FDTqSeg2; + uint8_t FDTqProp; + uint8_t FDTqSync; + uint16_t FDBRP; + uint8_t FDTDC; + uint8_t reserved; +} CANFD_SETTINGS; +#define CANFD_SETTINGS_SIZE 10 + +/* high_speed_auto_switch in SWCAN_SETTINGS */ +enum +{ + SWCAN_AUTOSWITCH_DISABLED, + SWCAN_AUTOSWITCH_NO_RESISTOR, + SWCAN_AUTOSWITCH_WITH_RESISTOR, + SWCAN_AUTOSWITCH_DISABLED_RESISTOR_ENABLED +}; + +typedef struct +{ + uint8_t Mode; + uint8_t SetBaudrate; + uint8_t Baudrate; + uint8_t transceiver_mode; + uint8_t TqSeg1; + uint8_t TqSeg2; + uint8_t TqProp; + uint8_t TqSync; + uint16_t BRP; + uint16_t high_speed_auto_switch; + uint8_t auto_baud; + uint8_t RESERVED; +} SWCAN_SETTINGS; +#define SWCAN_SETTINGS_SIZE 14 + +/* Baudrate in LIN_SETTINGS / ISO9141_KEYWORD2000_SETTINGS / UART_SETTINGS */ +enum +{ + BPS5000, + BPS10400, + BPS33333, + BPS50000, + BPS62500, + BPS71429, + BPS83333, + BPS100000, + BPS117647 +}; + +/* MasterResistor in LIN_SETTINGS */ +enum +{ + RESISTOR_ON, + RESISTOR_OFF +}; + +/* Mode in LIN_SETTINGS */ +enum +{ + SLEEP_MODE, + SLOW_MODE, + NORMAL_MODE, + FAST_MODE +}; + +typedef struct _LIN_SETTINGS +{ + uint32_t Baudrate; /* New products since FIREVNETEP should rely on this only */ + uint16_t spbrg; /* Precompiled to be 40Mhz/Baudrate/16 - 1. Only used in neoVI FIRE/FIREVNET(4dw) */ + uint8_t brgh; /* Must be zero */ + uint8_t numBitsDelay; + uint8_t MasterResistor; + uint8_t Mode; +} LIN_SETTINGS; +#define LIN_SETTINGS_SIZE 10 + +typedef struct +{ + uint16_t time_500us; + uint16_t k; + uint16_t l; +} ISO9141_KEYWORD2000__INIT_STEP; +#define ISO9141_KEYWORD2000__INIT_STEP_SIZE 6 + +typedef struct +{ + uint32_t Baudrate; + uint16_t spbrg; + uint16_t brgh; + ISO9141_KEYWORD2000__INIT_STEP init_steps[16]; + uint8_t init_step_count; + uint16_t p2_500us; + uint16_t p3_500us; + uint16_t p4_500us; + uint16_t chksum_enabled; +} ISO9141_KEYWORD2000_SETTINGS; +#define ISO9141_KEYWORD2000_SETTINGS_SIZE 114 + +typedef struct _UART_SETTINGS +{ + uint16_t Baudrate; + uint16_t spbrg; + uint16_t brgh; + uint16_t parity; + uint16_t stop_bits; + uint8_t flow_control; /* 0- off, 1 - Simple CTS RTS */ + uint8_t reserved_1; + union { + uint32_t bOptions; + struct + { + unsigned invert_tx : 1; + unsigned invert_rx : 1; + unsigned half_duplex : 1; + unsigned reserved_bits : 13; + unsigned reserved_bits2 : 16; + }; + }; +} UART_SETTINGS; +#define UART_SETTINGS_SIZE 16 + +#ifdef __cplusplus +} // End of the namespace +#endif + +#endif \ No newline at end of file diff --git a/device/neovifire2/include/neovifire2settings.h b/device/neovifire2/include/neovifire2settings.h new file mode 100644 index 0000000..fc9c8ba --- /dev/null +++ b/device/neovifire2/include/neovifire2settings.h @@ -0,0 +1,129 @@ +#ifndef __NEOVIFIRE2SETTINGS_H_ +#define __NEOVIFIRE2SETTINGS_H_ + +#include +#include "device/include/idevicesettings.h" + +#pragma pack(push, 2) +typedef struct { + uint16_t perf_en; + + CAN_SETTINGS can1; + CANFD_SETTINGS canfd1; + CAN_SETTINGS can2; + CANFD_SETTINGS canfd2; + CAN_SETTINGS can3; + CANFD_SETTINGS canfd3; + CAN_SETTINGS can4; + CANFD_SETTINGS canfd4; + CAN_SETTINGS can5; + CANFD_SETTINGS canfd5; + CAN_SETTINGS can6; + CANFD_SETTINGS canfd6; + CAN_SETTINGS can7; + CANFD_SETTINGS canfd7; + CAN_SETTINGS can8; + CANFD_SETTINGS canfd8; + + /* Native CAN are either LS1/LS2 or SW1/SW2 */ + SWCAN_SETTINGS swcan1; + uint16_t network_enables; + SWCAN_SETTINGS swcan2; + uint16_t network_enables_2; + + CAN_SETTINGS lsftcan1; + CAN_SETTINGS lsftcan2; + + LIN_SETTINGS lin1; + uint16_t misc_io_initial_ddr; + LIN_SETTINGS lin2; + uint16_t misc_io_initial_latch; + LIN_SETTINGS lin3; + uint16_t misc_io_report_period; + LIN_SETTINGS lin4; + uint16_t misc_io_on_report_events; + LIN_SETTINGS lin5; + uint16_t misc_io_analog_enable; + uint16_t ain_sample_period; + uint16_t ain_threshold; + + uint32_t pwr_man_timeout; + uint16_t pwr_man_enable; + + uint16_t network_enabled_on_boot; + + uint16_t iso15765_separation_time_offset; + + uint16_t iso_9141_kwp_enable_reserved; + ISO9141_KEYWORD2000_SETTINGS iso9141_kwp_settings_1; + uint16_t iso_parity_1; + + ISO9141_KEYWORD2000_SETTINGS iso9141_kwp_settings_2; + uint16_t iso_parity_2; + + ISO9141_KEYWORD2000_SETTINGS iso9141_kwp_settings_3; + uint16_t iso_parity_3; + + ISO9141_KEYWORD2000_SETTINGS iso9141_kwp_settings_4; + uint16_t iso_parity_4; + + uint16_t iso_msg_termination_1; + uint16_t iso_msg_termination_2; + uint16_t iso_msg_termination_3; + uint16_t iso_msg_termination_4; + + uint16_t idle_wakeup_network_enables_1; + uint16_t idle_wakeup_network_enables_2; + + /* reserved for HSCAN6/7, LSFT2, etc.. */ + uint16_t network_enables_3; + uint16_t idle_wakeup_network_enables_3; + + uint16_t can_switch_mode; + STextAPISettings text_api; + uint64_t termination_enables; + LIN_SETTINGS lin6; + ETHERNET_SETTINGS ethernet; + uint16_t slaveVnetA; + uint16_t slaveVnetB; + struct { + uint32_t disableUsbCheckOnBoot : 1; + uint32_t enableLatencyTest : 1; + uint32_t busMessagesToAndroid : 1; + uint32_t enablePcEthernetComm : 1; + uint32_t enableDefaultLogger : 1; + uint32_t enableDefaultUpload : 1; + uint32_t reserved : 26; + } flags; + uint16_t digitalIoThresholdTicks; + uint16_t digitalIoThresholdEnable; + TIMESYNC_ICSHARDWARE_SETTINGS timeSync; +} neovifire2_settings_t; +#pragma pack(pop) + +#ifdef __cplusplus + +#include + +namespace icsneo { + +class NeoVIFIRE2Settings : public IDeviceSettings { +public: + void refresh() { + IDeviceSettings::refresh(); + if(settingsLoaded) { + if(settings.size() != sizeof(neovifire2_settings_t)) { + std::cout << "Settings size was " << settings.size() << " but for a FIRE2 it should be " << sizeof(neovifire2_settings_t) << std::endl; + settingsLoaded = false; + } + } + } +private: + neovifire2_settings_t* settingsStruct = (neovifire2_settings_t*)settings.data(); +}; + +} + +#endif // __cplusplus + +#endif \ No newline at end of file