diff --git a/communication/communication.cpp b/communication/communication.cpp index 716076d..22d6e0a 100644 --- a/communication/communication.cpp +++ b/communication/communication.cpp @@ -68,19 +68,20 @@ bool Communication::getSettingsSync(std::vector& data, std::chrono::mil return true; } -bool Communication::getSerialNumberSync(std::string& serial, std::chrono::milliseconds timeout) { +std::shared_ptr Communication::getSerialNumberSync(std::chrono::milliseconds timeout) { sendCommand(Command::RequestSerialNumber); - std::shared_ptr msg = waitForMessageSync(MessageFilter(Network::NetID::RED_OLDFORMAT), 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; + std::shared_ptr msg = waitForMessageSync(std::make_shared(Command::RequestSerialNumber), timeout); + if(!msg) { + std::cout << "Didn't get a message in time" << std::endl; + return std::shared_ptr(); } - return true; + auto m51 = std::dynamic_pointer_cast(msg); + if(!m51) { + std::cout << "msg could not be cast to main51 " << msg->network << std::endl; + return std::shared_ptr(); + } + + return std::dynamic_pointer_cast(m51); } int Communication::addMessageCallback(const MessageCallback& cb) { @@ -97,7 +98,7 @@ bool Communication::removeMessageCallback(int id) { } } -std::shared_ptr Communication::waitForMessageSync(MessageFilter f, std::chrono::milliseconds timeout) { +std::shared_ptr Communication::waitForMessageSync(std::shared_ptr f, std::chrono::milliseconds timeout) { std::mutex m; std::condition_variable cv; std::shared_ptr returnedMessage; diff --git a/communication/include/communication.h b/communication/include/communication.h index 977a7e8..796bf0a 100644 --- a/communication/include/communication.h +++ b/communication/include/communication.h @@ -33,13 +33,14 @@ public: 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(50)); - bool getSerialNumberSync(std::string& serial, std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); + std::shared_ptr getSerialNumberSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); int addMessageCallback(const MessageCallback& cb); bool removeMessageCallback(int id); - std::shared_ptr waitForMessageSync(MessageFilter f = MessageFilter(), std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); - - void setAlign16Bit(bool enable) { align16bit = enable; } + std::shared_ptr waitForMessageSync(MessageFilter f = MessageFilter(), std::chrono::milliseconds timeout = std::chrono::milliseconds(50)) { + return waitForMessageSync(std::make_shared(f), timeout); + } + std::shared_ptr waitForMessageSync(std::shared_ptr f, std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); std::shared_ptr packetizer; std::shared_ptr decoder; @@ -52,7 +53,6 @@ protected: private: bool isOpen = false; - bool align16bit = true; // Not needed for Gigalog, Galaxy, etc and newer std::thread readTaskThread; void readTask(); diff --git a/communication/messagedecoder.cpp b/communication/messagedecoder.cpp index 3819d37..1dbad89 100644 --- a/communication/messagedecoder.cpp +++ b/communication/messagedecoder.cpp @@ -1,5 +1,6 @@ #include "communication/include/messagedecoder.h" #include "communication/include/communication.h" +#include "communication/message/include/serialnumbermessage.h" #include "communication/include/command.h" #include "device/include/device.h" #include @@ -33,7 +34,42 @@ std::shared_ptr MessageDecoder::decodePacket(const std::shared_ptrnetwork.getNetID()) { + case Network::NetID::Main51: { + switch((Command)packet->data[0]) { + case Command::RequestSerialNumber: { + auto msg = std::make_shared(); + msg->network = packet->network; + uint64_t serial = GetUInt64FromLEBytes(packet->data.data() + 1); + // The device sends 64-bits of serial number, but we never use more than 32-bits. + msg->deviceSerial = Device::SerialNumToString((uint32_t)serial); + msg->hasMacAddress = packet->data.size() >= 15; + if(msg->hasMacAddress) + memcpy(msg->macAddress, packet->data.data() + 9, sizeof(msg->macAddress)); + msg->hasPCBSerial = packet->data.size() >= 31; + if(msg->hasPCBSerial) + memcpy(msg->pcbSerial, packet->data.data() + 15, sizeof(msg->pcbSerial)); + return msg; + } + } + break; + } + case Network::NetID::RED_OLDFORMAT: { + /* So-called "old format" messages are a "new style, long format" wrapper around the old short messages. + * They consist of a 16-bit LE length first, then the 8-bit length and netid combo byte, then the payload + * with no checksum. The upper-nibble length of the combo byte should be ignored completely, using the + * length from the first two bytes in it's place. Ideally, we never actually send the oldformat messages + * out to the rest of the application as they can recursively get decoded to another message type here. + * Feed the result back into the decoder in case we do something special with the resultant netid. + */ + uint16_t length = packet->data[0] | (packet->data[1] << 8); + packet->network = Network(packet->data[2] & 0xF); + packet->data.erase(packet->data.begin(), packet->data.begin() + 3); + if(packet->data.size() != length) + packet->data.resize(length); + return decodePacket(packet); + } + } break; } diff --git a/communication/packetizer.cpp b/communication/packetizer.cpp index e763f84..9250e28 100644 --- a/communication/packetizer.cpp +++ b/communication/packetizer.cpp @@ -54,7 +54,7 @@ bool Packetizer::input(const std::vector& inputBytes) { headerSize = 6; } else { state = ReadState::GetData; - checksum = true; + checksum = true; // Even if checksum is not explicitly disallowed, we enable it here, as this goes into length calculation headerSize = 2; packetLength += 2; // The packet length given in short packets does not include header } @@ -99,10 +99,10 @@ bool Packetizer::input(const std::vector& inputBytes) { while(currentIndex < packetLength) packet.data[i++] = bytes[currentIndex++]; - if(!checksum || bytes[currentIndex] == Communication::ICSChecksum(packet.data)) { + if(disableChecksum || !checksum || bytes[currentIndex] == ICSChecksum(packet.data)) { // Got a good packet gotGoodPackets = true; - processedPackets.push_back(std::make_shared(packet)); + processedPackets.push_back(std::make_shared(packet)); for (auto a = 0; a < packetLength; a++) bytes.pop_front(); } else { diff --git a/device/device.cpp b/device/device.cpp index 6c8155a..103361d 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -123,10 +123,37 @@ bool Device::open() { if(!com) return false; + if(!com->open()) + return false; + + auto serial = com->getSerialNumberSync(); + int i = 0; + while(!serial) { + serial = com->getSerialNumberSync(); + if(i++ > 5) + break; + } + if(!serial) { + std::cout << "Failed to get serial number in " << i << " tries" << std::endl; + return false; + } + + if(i != 0) + std::cout << "Took " << i << " tries to get the serial number" << std::endl; + + std::string currentSerial = getNeoDevice().serial; + if(currentSerial == SERIAL_FIND_ON_OPEN) { + strncpy(getWritableNeoDevice().serial, serial->deviceSerial.c_str(), sizeof(getNeoDevice().serial)); + getWritableNeoDevice().serial[sizeof(getWritableNeoDevice().serial) - 1] = '\0'; + } else if(currentSerial != serial->deviceSerial) { + std::cout << "NeoDevice has serial " << getNeoDevice().serial << " but device has serial " << serial->deviceSerial.c_str() << "!" << std::endl; + return false; + } + if(settings) settings->refresh(); - return com->open(); + return true; } bool Device::close() { @@ -141,7 +168,7 @@ bool Device::close() { bool Device::goOnline() { if(!com->sendCommand(Command::EnableNetworkCommunication, true)) return false; - + online = true; return true; } diff --git a/device/include/device.h b/device/include/device.h index ceea119..f2238ef 100644 --- a/device/include/device.h +++ b/device/include/device.h @@ -15,6 +15,8 @@ namespace icsneo { class Device { public: + static constexpr char* SERIAL_FIND_ON_OPEN = "xxxxxx"; + Device(neodevice_t neodevice = {}) { data = neodevice; data.device = this; diff --git a/platform/windows/pcap.cpp b/platform/windows/pcap.cpp index 3dd2e3b..7f924e6 100644 --- a/platform/windows/pcap.cpp +++ b/platform/windows/pcap.cpp @@ -134,13 +134,15 @@ std::vector PCAP::FindByProduct(int product) { if(product != packet.srcMAC[3]) // This is where the PID is stored in the MAC continue; // This is not a product we're currently looking for - std::string serialFromMAC = GetEthDevSerialFromMacAddress(packet.srcMAC[3], ((packet.srcMAC[4] << 8) | packet.srcMAC[5])); neodevice_t neodevice; - #pragma warning(push) - #pragma warning(disable:4996) - strncpy(neodevice.serial, serialFromMAC.c_str(), sizeof(neodevice.serial)); - neodevice.serial[sizeof(neodevice.serial) - 1] = 0; - #pragma warning(pop) + /* Unlike other transport layers, we can't get the serial number here as we + * actually need to open the device in the find method and then request it + * over a working communication layer. We could technically create a communication + * layer to parse the packet we have in `data` at this point, but we'd need to + * know information about the device to correctly instantiate a packetizer and + * decoder. I'm intentionally avoiding passing that information down here for + * code quality's sake. + */ neodevice.handle = (neodevice_handle_t)((i << 24) | (packet.srcMAC[3] << 16) | (packet.srcMAC[4] << 8) | (packet.srcMAC[5])); bool alreadyExists = false; for(auto& dev : foundDevices)