Start work on device settings communication

pull/4/head
Paul Hollinsky 2018-09-24 16:57:14 -04:00
parent af4f4894f5
commit da4d9e46be
9 changed files with 574 additions and 13 deletions

View File

@ -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
)

View File

@ -4,6 +4,8 @@
#include <queue>
#include <iomanip>
#include <cstring>
#include <mutex>
#include <condition_variable>
#include "communication/include/messagedecoder.h"
#include "communication/include/packetizer.h"
@ -67,10 +69,34 @@ bool Communication::sendCommand(Communication::Command cmd, std::vector<uint8_t>
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<uint8_t>& data, std::chrono::milliseconds timeout) {
sendCommand(Command::GetSettings);
std::shared_ptr<Message> 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<Message> 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<Message> Communication::waitForMessageSync(MessageFilter f, std::chrono::milliseconds timeout) {
std::mutex m;
std::condition_variable cv;
std::shared_ptr<Message> returnedMessage;
int cb = addMessageCallback(MessageCallback([&m, &returnedMessage, &cv](std::shared_ptr<Message> message) {
{
std::lock_guard<std::mutex> 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<std::mutex> 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<uint8_t> readBytes;
Packetizer packetizer;

View File

@ -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>({ (uint8_t)boolean })); }
virtual bool sendCommand(Command cmd, std::vector<uint8_t> arguments = {});
bool getSettingsSync(std::vector<uint8_t>& 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<Message> waitForMessageSync(MessageFilter f = MessageFilter(), std::chrono::milliseconds timeout = std::chrono::milliseconds(10));
void setAlign16Bit(bool enable) { align16bit = enable; }

View File

@ -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:

View File

@ -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;
}

View File

@ -0,0 +1,76 @@
#include "device/include/idevicesettings.h"
using namespace icsneo;
uint16_t IDeviceSettings::CalculateGSChecksum(const std::vector<uint8_t>& 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<uint8_t> 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;
}
}

View File

@ -5,6 +5,7 @@
#include <memory>
#include <cstring>
#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<IDeviceSettings> settings;
protected:
uint16_t productId = 0;
bool online = false;

View File

@ -0,0 +1,227 @@
#ifndef __IDEVICESETTINGS_H_
#define __IDEVICESETTINGS_H_
#include <stdint.h>
#ifdef __cplusplus
#include "communication/include/communication.h"
#include <iostream>
namespace icsneo {
class IDeviceSettings {
public:
static uint16_t CalculateGSChecksum(const std::vector<uint8_t>& settings);
IDeviceSettings(std::shared_ptr<Communication> 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<uint8_t> settings;
std::shared_ptr<Communication> 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

View File

@ -0,0 +1,129 @@
#ifndef __NEOVIFIRE2SETTINGS_H_
#define __NEOVIFIRE2SETTINGS_H_
#include <stdint.h>
#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 <iostream>
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