From 564933cb41a5673ae6d813aba5f6e43ce4acabad Mon Sep 17 00:00:00 2001 From: Kyle Schwarz Date: Wed, 21 Aug 2024 10:42:04 -0400 Subject: [PATCH] Device: Add readCoreminiHeader() - Fixes NeoMemoryDiskDriver::readLogicalDiskAligned() for flash - Adds FlashMemoryMessage --- communication/decoder.cpp | 13 +++ device/device.cpp | 79 +++++++++++++++++++ disk/neomemorydiskdriver.cpp | 28 ++++--- .../message/flashmemorymessage.h | 20 +++++ include/icsneo/communication/network.h | 1 + include/icsneo/device/coremini.h | 28 +++++++ include/icsneo/device/device.h | 3 + 7 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 include/icsneo/communication/message/flashmemorymessage.h create mode 100644 include/icsneo/device/coremini.h diff --git a/communication/decoder.cpp b/communication/decoder.cpp index 1400c9c..ac00464 100644 --- a/communication/decoder.cpp +++ b/communication/decoder.cpp @@ -5,6 +5,7 @@ #include "icsneo/communication/message/readsettingsmessage.h" #include "icsneo/communication/message/canerrorcountmessage.h" #include "icsneo/communication/message/neoreadmemorysdmessage.h" +#include "icsneo/communication/message/flashmemorymessage.h" #include "icsneo/communication/message/extendedresponsemessage.h" #include "icsneo/communication/message/wiviresponsemessage.h" #include "icsneo/communication/message/scriptstatusmessage.h" @@ -257,6 +258,18 @@ bool Decoder::decode(std::shared_ptr& result, const std::shared_ptr(packet->network, packet->data); return true; } + case Network::NetID::RED_INT_MEMORYREAD: { + if(packet->data.size() != 512 + sizeof(uint16_t)) { + report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); + return false; // Should get enough data for a start address and sector + } + + const auto msg = std::make_shared(); + result = msg; + msg->startAddress = *reinterpret_cast(packet->data.data()); + msg->data.insert(msg->data.end(), packet->data.begin() + 2, packet->data.end()); + return true; + } case Network::NetID::NeoMemorySDRead: { if(packet->data.size() != 512 + sizeof(uint32_t)) { report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); diff --git a/device/device.cpp b/device/device.cpp index a1d61a2..cfdec32 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -656,6 +656,85 @@ bool Device::clearScript(Disk::MemoryType memType) return true; } +std::optional Device::readCoreminiHeader(Disk::MemoryType memType) { + if(!isOpen()) { + report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error); + return std::nullopt; + } + + auto startAddress = getCoreminiStartAddress(memType); + if(!startAddress) { + return std::nullopt; + } + + auto connected = isLogicalDiskConnected(); + + if(!connected) { + return std::nullopt; // Already added an API error + } + + #pragma pack(push, 2) + struct RawCoreminiHeader { + uint16_t fileType; + uint16_t fileVersion; + uint32_t storedFileSize; + uint32_t fileChecksum; + union + { + struct + { + uint32_t skipDecompression : 1; + uint32_t encryptedMode : 1; + uint32_t reserved : 30; + } bits; + uint32_t word; + } flags; + uint8_t fileHash[32]; + union + { + struct + { + uint32_t lsb; + uint32_t msb; + } words; + uint64_t time64; + } createTime; + uint8_t reserved[8]; + }; + #pragma pack(pop) + + RawCoreminiHeader header = {}; + auto numRead = readLogicalDisk(*startAddress, (uint8_t*)&header, sizeof(header), std::chrono::milliseconds(2000), memType); + + if(!numRead) { + return std::nullopt; // Already added an API error + } + + if(*numRead != sizeof(header)) { + report(APIEvent::Type::FailedToRead, APIEvent::Severity::Error); + return std::nullopt; + } + + if(header.fileType != 0x0907) { + report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error); + return std::nullopt; + } + + std::optional ret; + ret.emplace(); + ret->coreminiVersion = header.fileVersion; + ret->storedFileSize = header.storedFileSize; + ret->fileChecksum = header.fileChecksum; + ret->skipDecompression = static_cast(header.flags.bits.skipDecompression); + ret->encryptedMode = static_cast(header.flags.bits.encryptedMode); + std::copy(std::begin(header.fileHash), std::end(header.fileHash), ret->fileHash.begin()); + static constexpr std::chrono::seconds icsEpochDelta(1167609600); + static constexpr uint8_t timestampResolution = 25; + static constexpr uint16_t nsInUs = 1'000; + ret->timestamp += icsEpochDelta + std::chrono::microseconds(header.createTime.time64 * timestampResolution / nsInUs); + return ret; +} + bool Device::transmit(std::shared_ptr frame) { if(!isOpen()) { report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error); diff --git a/disk/neomemorydiskdriver.cpp b/disk/neomemorydiskdriver.cpp index b5474cb..fa75819 100644 --- a/disk/neomemorydiskdriver.cpp +++ b/disk/neomemorydiskdriver.cpp @@ -1,5 +1,6 @@ #include "icsneo/disk/neomemorydiskdriver.h" #include "icsneo/communication/message/neoreadmemorysdmessage.h" +#include "icsneo/communication/message/flashmemorymessage.h" #include #include @@ -8,7 +9,8 @@ using namespace icsneo::Disk; std::optional NeoMemoryDiskDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report, uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, MemoryType memType) { - static std::shared_ptr NeoMemorySDRead = std::make_shared(Network::NetID::NeoMemorySDRead); + const auto filter = std::make_shared((memType == MemoryType::SD ? Network::NetID::NeoMemorySDRead : Network::NetID::RED_INT_MEMORYREAD)); + filter->includeInternalInAny = true; if(pos % SectorSize != 0) return std::nullopt; @@ -20,7 +22,7 @@ std::optional NeoMemoryDiskDriver::readLogicalDiskAligned(Communicatio const uint8_t memLocation = (uint8_t)memType; uint64_t numWords = amount / 2; - + auto msg = com.waitForMessageSync([¤tSector, &memLocation, &com, &numWords] { return com.sendCommand(Command::NeoReadMemory, { memLocation, @@ -33,18 +35,26 @@ std::optional NeoMemoryDiskDriver::readLogicalDiskAligned(Communicatio uint8_t((numWords >> 16) & 0xFF), uint8_t((numWords >> 24) & 0xFF) }); - }, NeoMemorySDRead, timeout); + }, filter, timeout); if(!msg) return 0; - const auto sdmsg = std::dynamic_pointer_cast(msg); - if(!sdmsg || sdmsg->data.size() != SectorSize) { - report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); - return std::nullopt; + if(memType == MemoryType::SD) { + const auto mem = std::dynamic_pointer_cast(msg); + if(!mem || mem->data.size() != SectorSize) { + report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); + return std::nullopt; + } + memcpy(into, mem->data.data(), SectorSize); + } else { // flash + const auto mem = std::dynamic_pointer_cast(msg); + if(!mem || mem->data.size() != SectorSize) { + report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); + return std::nullopt; + } + memcpy(into, mem->data.data(), SectorSize); } - - memcpy(into, sdmsg->data.data(), SectorSize); return SectorSize; } diff --git a/include/icsneo/communication/message/flashmemorymessage.h b/include/icsneo/communication/message/flashmemorymessage.h new file mode 100644 index 0000000..4ac2e6b --- /dev/null +++ b/include/icsneo/communication/message/flashmemorymessage.h @@ -0,0 +1,20 @@ +#ifndef __FLASHMEMORYMESSAGE_H_ +#define __FLASHMEMORYMESSAGE_H_ + +#ifdef __cplusplus + +#include "icsneo/communication/message/message.h" + +namespace icsneo { + +class FlashMemoryMessage : public RawMessage { +public: + FlashMemoryMessage() : RawMessage(Message::Type::RawMessage, Network::NetID::RED_INT_MEMORYREAD) {} + uint16_t startAddress = 0; +}; + +} + +#endif // __cplusplus + +#endif \ No newline at end of file diff --git a/include/icsneo/communication/network.h b/include/icsneo/communication/network.h index 613d3fc..55688d3 100644 --- a/include/icsneo/communication/network.h +++ b/include/icsneo/communication/network.h @@ -533,6 +533,7 @@ public: case NetID::CoreMiniPreLoad: case NetID::ExtendedCommand: case NetID::ExtendedData: + case NetID::RED_INT_MEMORYREAD: case NetID::NeoMemorySDRead: case NetID::NeoMemoryWriteDone: case NetID::RED_GET_RTC: diff --git a/include/icsneo/device/coremini.h b/include/icsneo/device/coremini.h new file mode 100644 index 0000000..05bd8c3 --- /dev/null +++ b/include/icsneo/device/coremini.h @@ -0,0 +1,28 @@ +#ifndef __COREMINI_H_ +#define __COREMINI_H_ + +#ifdef __cplusplus + +#include +#include +#include + +namespace icsneo { + +struct CoreminiHeader { + uint16_t coreminiVersion; + uint32_t storedFileSize; + // 32-bit word checksum on the entire (decompressed) binary, with the checksum and hash fields set to 0 + uint32_t fileChecksum; + // SHA256 hash of the entire (decompressed) binary, with the checksum, hash, and create time fields set to 0 + bool skipDecompression; + bool encryptedMode; + std::array fileHash; + std::chrono::time_point timestamp; +}; + +} + +#endif // __cplusplus + +#endif \ No newline at end of file diff --git a/include/icsneo/device/device.h b/include/icsneo/device/device.h index dc1ce01..169cbc1 100644 --- a/include/icsneo/device/device.h +++ b/include/icsneo/device/device.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "icsneo/api/eventmanager.h" #include "icsneo/api/lifetime.h" #include "icsneo/device/neodevice.h" @@ -21,6 +22,7 @@ #include "icsneo/device/devicetype.h" #include "icsneo/device/deviceversion.h" #include "icsneo/device/founddevice.h" +#include "icsneo/device/coremini.h" #include "icsneo/disk/diskreaddriver.h" #include "icsneo/disk/diskwritedriver.h" #include "icsneo/disk/nulldiskdriver.h" @@ -163,6 +165,7 @@ public: bool stopScript(); bool clearScript(Disk::MemoryType memType = Disk::MemoryType::SD); bool uploadCoremini(std::istream& stream, Disk::MemoryType memType = Disk::MemoryType::SD); + std::optional readCoreminiHeader(Disk::MemoryType memType = Disk::MemoryType::SD); bool eraseScriptMemory(Disk::MemoryType memType, uint64_t amount);