diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e110ca..17141f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ endif() set(COMMON_SRC communication/message/neomessage.cpp communication/decoder.cpp + communication/encoder.cpp communication/packetizer.cpp communication/multichannelcommunication.cpp communication/communication.cpp diff --git a/communication/communication.cpp b/communication/communication.cpp index 7940f79..cbbe168 100644 --- a/communication/communication.cpp +++ b/communication/communication.cpp @@ -46,16 +46,20 @@ bool Communication::close() { } bool Communication::sendPacket(std::vector& bytes) { - return rawWrite(packetizer->packetWrap(bytes)); + std::cout << "\nWriting " << bytes.size() << " bytes\n" << std::hex; + for(size_t i = 0; i < bytes.size(); i++) + std::cout << std::setw(2) << std::setfill('0') << (int)bytes[i] << (i % 16 == 15 ? '\n' : ' '); + std::cout << '\n' << std::endl << std::dec; + return rawWrite(bytes); } bool Communication::sendCommand(Command cmd, std::vector arguments) { - std::vector bytes; - bytes.push_back((uint8_t)cmd); - for(auto& b : arguments) - bytes.push_back(b); - bytes.insert(bytes.begin(), (uint8_t)Network::NetID::Main51 | ((uint8_t)bytes.size() << 4)); - return sendPacket(bytes); + auto msg = std::make_shared(); + msg->network = Network::NetID::Main51; + msg->data = std::move(arguments); + msg->data.insert(msg->data.begin(), (uint8_t)cmd); + auto packet = encoder->encode(msg); + return sendPacket(packet); } bool Communication::getSettingsSync(std::vector& data, std::chrono::milliseconds timeout) { @@ -130,6 +134,7 @@ void Communication::readTask() { if(packetizer->input(readBytes)) { for(auto& packet : packetizer->output()) { auto msg = decoder->decodePacket(packet); + std::cout << "Got packet for " << msg->network << ", calling " << messageCallbacks.size() << " callbacks" << std::endl; for(auto& cb : messageCallbacks) { // We might have closed while reading or processing if(!closing) { cb.second.callIfMatch(msg); diff --git a/communication/decoder.cpp b/communication/decoder.cpp index 57aeb4f..cd01889 100644 --- a/communication/decoder.cpp +++ b/communication/decoder.cpp @@ -64,6 +64,7 @@ std::shared_ptr Decoder::decodePacket(const std::shared_ptr& pa */ uint16_t length = packet->data[0] | (packet->data[1] << 8); packet->network = Network(packet->data[2] & 0xF); + std::cout << "Got an old format packet, decoding against " << packet->network << std::endl; packet->data.erase(packet->data.begin(), packet->data.begin() + 3); if(packet->data.size() != length) packet->data.resize(length); diff --git a/communication/encoder.cpp b/communication/encoder.cpp index 7740c4d..9100c24 100644 --- a/communication/encoder.cpp +++ b/communication/encoder.cpp @@ -2,7 +2,8 @@ using namespace icsneo; -std::shared_ptr Encoder::encode(const std::shared_ptr& message) { +std::vector Encoder::encode(const std::shared_ptr& message) { + bool shortFormat = false; switch(message->network.getType()) { // case Network::Type::CAN: { // if(message->data.size() < 24) @@ -24,34 +25,40 @@ std::shared_ptr Encoder::encode(const std::shared_ptr& message default: switch(message->network.getNetID()) { case Network::NetID::Main51: - if(message->data.size() > 0xF) { - message->network = Network::NetID::RED_OLDFORMAT; - message->data.insert(message->data.begin(), 0x10 | (uint8_t)Network::NetID::Main51); - return encode(message); - } - message->data.insert(message->data.begin(), (message->data.size() << 4) | (uint8_t)Network::NetID::Main51); - data.in + if(message->data.size() <= 0xF) + shortFormat = true; break; case Network::NetID::RED_OLDFORMAT: { // See the decoder for an explanation - uint16_t length = message->data[0] | (message->data[1] << 8); - message->network = Network(message->data[2] & 0xF); - message->data.erase(message->data.begin(), message->data.begin() + 3); - if(message->data.size() != length) - message->data.resize(length); - return decodePacket(message); + // We expect the network byte to be populated already in data, but not the length + uint16_t length = message->data.size() - 1; + message->data.insert(message->data.begin(), {(uint8_t)length, (uint8_t)(length >> 8)}); } + default: + break; } break; } - auto msg = std::make_shared(); - msg->network = message->network; - msg->data = message->data; - return msg; + if(shortFormat) { + message->data.insert(message->data.begin(), (message->data.size() << 4) | (uint8_t)message->network.getNetID()); + } else { + // Size in long format is the size of the entire packet + // So +1 for AA header, +1 for short format header, +2 for long format size, and +2 for long format NetID + uint16_t size = message->data.size() + 1 + 1 + 2 + 2; + message->data.insert(message->data.begin(), { + (uint8_t)Network::NetID::RED, // 0x0C for long message + (uint8_t)size, // Size, little endian 16-bit + (uint8_t)(size >> 8), + (uint8_t)message->network.getNetID(), // NetID, little endian 16-bit + (uint8_t)(uint16_t(message->network.getNetID()) >> 8) + }); + } + + return packetizer->packetWrap(message->data, shortFormat); } -std::vector Encoder::encode(Command cmd, std::vector arguments = {}) { +std::vector Encoder::encode(Command cmd, std::vector arguments) { auto msg = std::make_shared(); msg->network = Network::NetID::Main51; msg->data.resize(arguments.size() + 1); diff --git a/communication/include/communication.h b/communication/include/communication.h index d8b0a17..5c05ab3 100644 --- a/communication/include/communication.h +++ b/communication/include/communication.h @@ -8,6 +8,7 @@ #include "communication/message/callback/include/messagecallback.h" #include "communication/message/include/serialnumbermessage.h" #include "communication/include/packetizer.h" +#include "communication/include/encoder.h" #include "communication/include/decoder.h" #include #include @@ -20,7 +21,11 @@ namespace icsneo { class Communication { public: - Communication(std::shared_ptr com, std::shared_ptr p, std::shared_ptr md) : packetizer(p), decoder(md), impl(com) {} + Communication( + std::shared_ptr com, + std::shared_ptr p, + std::shared_ptr e, + std::shared_ptr md) : packetizer(p), encoder(e), decoder(md), impl(com) {} virtual ~Communication() { close(); } bool open(); @@ -43,6 +48,7 @@ public: std::shared_ptr waitForMessageSync(std::shared_ptr f, std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); std::shared_ptr packetizer; + std::shared_ptr encoder; std::shared_ptr decoder; protected: diff --git a/communication/include/encoder.h b/communication/include/encoder.h index e55db16..6f76ef5 100644 --- a/communication/include/encoder.h +++ b/communication/include/encoder.h @@ -4,7 +4,9 @@ #include "communication/message/include/message.h" #include "communication/message/include/canmessage.h" #include "communication/include/packet.h" +#include "communication/include/command.h" #include "communication/include/network.h" +#include "communication/include/packetizer.h" #include #include #include @@ -15,11 +17,14 @@ namespace icsneo { class Encoder { public: + Encoder(std::shared_ptr packetizerInstance) : packetizer(packetizerInstance) {} std::vector encode(const std::shared_ptr& message); std::vector encode(Command cmd, bool boolean) { return encode(cmd, std::vector({ (uint8_t)boolean })); } std::vector encode(Command cmd, std::vector arguments = {}); private: + std::shared_ptr packetizer; + typedef uint16_t icscm_bitfield; struct HardwareCANPacket { struct { diff --git a/communication/include/multichannelcommunication.h b/communication/include/multichannelcommunication.h index fb23f99..e3a9e04 100644 --- a/communication/include/multichannelcommunication.h +++ b/communication/include/multichannelcommunication.h @@ -4,12 +4,17 @@ #include "communication/include/communication.h" #include "communication/include/icommunication.h" #include "communication/include/command.h" +#include "communication/include/encoder.h" namespace icsneo { class MultiChannelCommunication : public Communication { public: - MultiChannelCommunication(std::shared_ptr com, std::shared_ptr p, std::shared_ptr md) : Communication(com, p, md) {} + MultiChannelCommunication( + std::shared_ptr com, + std::shared_ptr p, + std::shared_ptr e, + std::shared_ptr md) : Communication(com, p, e, md) {} void spawnThreads() override; void joinThreads() override; bool sendPacket(std::vector& bytes) override; diff --git a/communication/include/packetizer.h b/communication/include/packetizer.h index 234a17b..c11d9a8 100644 --- a/communication/include/packetizer.h +++ b/communication/include/packetizer.h @@ -11,7 +11,7 @@ namespace icsneo { class Packetizer { public: static uint8_t ICSChecksum(const std::vector& data); - std::vector& packetWrap(std::vector& data, bool checksum = true); + std::vector& packetWrap(std::vector& data, bool shortFormat); bool input(const std::vector& bytes); std::vector> output(); diff --git a/communication/packetizer.cpp b/communication/packetizer.cpp index d024156..d6157bb 100644 --- a/communication/packetizer.cpp +++ b/communication/packetizer.cpp @@ -1,5 +1,6 @@ #include "communication/include/packetizer.h" #include +#include using namespace icsneo; @@ -12,12 +13,15 @@ uint8_t Packetizer::ICSChecksum(const std::vector& data) { return (uint8_t)checksum; } -std::vector& Packetizer::packetWrap(std::vector& data, bool checksum) { - if(!disableChecksum && checksum) - data.push_back(ICSChecksum(data)); +std::vector& Packetizer::packetWrap(std::vector& data, bool shortFormat) { + if(shortFormat) { + // Some devices don't use the checksum, so might as well not calculate it if that's the case + // Either way the byte is still expected to be present in the bytestream for short messages + data.push_back(disableChecksum ? 0x00 : ICSChecksum(data)); + } data.insert(data.begin(), 0xAA); - if(align16bit && data.size() % 2 == 1) - data.push_back('A'); + if(align16bit && data.size() % 2 == 1) // Some devices always expect 16-bit aligned data + data.push_back('A'); // Used as padding character, ignored by the firmware return data; } diff --git a/device/idevicesettings.cpp b/device/idevicesettings.cpp index d57f87a..1e2019d 100644 --- a/device/idevicesettings.cpp +++ b/device/idevicesettings.cpp @@ -95,7 +95,11 @@ bool IDeviceSettings::send() { bytestream[5] = gs_checksum >> 8; memcpy(bytestream.data() + 6, getRawStructurePointer(), structSize); com->sendCommand(Command::SetSettings, bytestream); - std::shared_ptr msg = com->waitForMessageSync(Main51MessageFilter(Command::SetSettings), std::chrono::milliseconds(500)); + std::shared_ptr msg = com->waitForMessageSync(std::make_shared(), std::chrono::milliseconds(3000)); + if(!msg) + std::cout << "No response from device for set settings" << std::endl; + if(msg && msg->data[1] != 1) + std::cout << "Response was incorrect for set settings: " << (int)msg->data[1] << std::endl; if(!msg || msg->data[1] != 1) { // The second byte of the response carries the result, 1 being success refresh(); // Refresh our buffer with what the device has return false; diff --git a/device/include/device.h b/device/include/device.h index dce8195..8264536 100644 --- a/device/include/device.h +++ b/device/include/device.h @@ -9,6 +9,7 @@ #include "device/include/devicetype.h" #include "communication/include/communication.h" #include "communication/include/packetizer.h" +#include "communication/include/encoder.h" #include "communication/include/decoder.h" #include "third-party/concurrentqueue/concurrentqueue.h" diff --git a/device/neovifire2/include/neovifire2eth.h b/device/neovifire2/include/neovifire2eth.h index 52bf61c..5dd2c8a 100644 --- a/device/neovifire2/include/neovifire2eth.h +++ b/device/neovifire2/include/neovifire2eth.h @@ -14,8 +14,9 @@ public: NeoVIFIRE2ETH(neodevice_t neodevice) : NeoVIFIRE2(neodevice) { auto transport = std::make_shared(getWritableNeoDevice()); auto packetizer = std::make_shared(); + auto encoder = std::make_shared(packetizer); auto decoder = std::make_shared(); - com = std::make_shared(transport, packetizer, decoder); + com = std::make_shared(transport, packetizer, encoder, decoder); settings = std::make_shared(com); productId = PRODUCT_ID; } diff --git a/device/neovifire2/include/neovifire2usb.h b/device/neovifire2/include/neovifire2usb.h index f172939..7224666 100644 --- a/device/neovifire2/include/neovifire2usb.h +++ b/device/neovifire2/include/neovifire2usb.h @@ -13,8 +13,9 @@ public: NeoVIFIRE2USB(neodevice_t neodevice) : NeoVIFIRE2(neodevice) { auto transport = std::make_shared(getWritableNeoDevice()); auto packetizer = std::make_shared(); + auto encoder = std::make_shared(packetizer); auto decoder = std::make_shared(); - com = std::make_shared(transport, packetizer, decoder); + com = std::make_shared(transport, packetizer, encoder, decoder); settings = std::make_shared(com); productId = PRODUCT_ID; }