diff --git a/CMakeLists.txt b/CMakeLists.txt index a62235b..79e4454 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,7 +152,7 @@ set(SRC_FILES disk/diskreaddriver.cpp disk/diskwritedriver.cpp disk/nulldiskdriver.cpp - disk/neomemorydiskreaddriver.cpp + disk/neomemorydiskdriver.cpp disk/plasiondiskreaddriver.cpp disk/extextractordiskreaddriver.cpp disk/fat.cpp diff --git a/disk/neomemorydiskdriver.cpp b/disk/neomemorydiskdriver.cpp new file mode 100644 index 0000000..a376080 --- /dev/null +++ b/disk/neomemorydiskdriver.cpp @@ -0,0 +1,92 @@ +#include "icsneo/disk/neomemorydiskdriver.h" +#include "icsneo/communication/message/neoreadmemorysdmessage.h" +#include + +using namespace icsneo; +using namespace icsneo::Disk; + +optional NeoMemoryDiskDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report, + uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) { + static std::shared_ptr NeoMemorySDRead = std::make_shared(Network::NetID::NeoMemorySDRead); + + if(pos % SectorSize != 0) + return nullopt; + + if(amount != SectorSize) + return nullopt; + + if(cachePos != pos || std::chrono::steady_clock::now() > cachedAt + CacheTime) { + // The cache does not have this data, go get it + const uint64_t currentSector = pos / SectorSize; + auto msg = com.waitForMessageSync([¤tSector, &com] { + return com.sendCommand(Command::NeoReadMemory, { + MemoryTypeSD, + uint8_t(currentSector & 0xFF), + uint8_t((currentSector >> 8) & 0xFF), + uint8_t((currentSector >> 16) & 0xFF), + uint8_t((currentSector >> 24) & 0xFF), + uint8_t(SectorSize & 0xFF), + uint8_t((SectorSize >> 8) & 0xFF), + uint8_t((SectorSize >> 16) & 0xFF), + uint8_t((SectorSize >> 24) & 0xFF) + }); + }, NeoMemorySDRead, 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 nullopt; + } + + memcpy(cache.data(), sdmsg->data.data(), SectorSize); + cachedAt = std::chrono::steady_clock::now(); + cachePos = pos; + } + + memcpy(into, cache.data(), SectorSize); + return SectorSize; +} + +optional NeoMemoryDiskDriver::writeLogicalDiskAligned(Communication& com, device_eventhandler_t report, + uint64_t pos, const uint8_t* atomicBuf, const uint8_t* from, uint64_t amount, std::chrono::milliseconds timeout) { + + static std::shared_ptr NeoMemoryDone = std::make_shared(Network::NetID::NeoMemoryWriteDone); + + if(pos % SectorSize != 0) + return nullopt; + + if(amount != SectorSize) + return nullopt; + + // Clear the cache if we're writing to the cached sector + if(pos == cachePos) + cachedAt = std::chrono::time_point(); + + // Requesting an atomic operation, but neoMemory does not support it + // Continue on anyway but warn the caller + if(atomicBuf != nullptr) + report(APIEvent::Type::AtomicOperationCompletedNonatomically, NonatomicSeverity); + + const uint64_t currentSector = pos / SectorSize; + auto msg = com.waitForMessageSync([¤tSector, &com, from, amount] { + std::vector command = { + MemoryTypeSD, + uint8_t(currentSector & 0xFF), + uint8_t((currentSector >> 8) & 0xFF), + uint8_t((currentSector >> 16) & 0xFF), + uint8_t((currentSector >> 24) & 0xFF), + uint8_t(SectorSize & 0xFF), + uint8_t((SectorSize >> 8) & 0xFF), + }; + command.insert(command.end(), from, from + amount); + return com.sendCommand(Command::NeoWriteMemory, command); + }, NeoMemoryDone, timeout); + + if(!msg) + return nullopt; + + return SectorSize; +} \ No newline at end of file diff --git a/disk/neomemorydiskreaddriver.cpp b/disk/neomemorydiskreaddriver.cpp deleted file mode 100644 index ef0d87d..0000000 --- a/disk/neomemorydiskreaddriver.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "icsneo/disk/neomemorydiskreaddriver.h" -#include "icsneo/communication/message/neoreadmemorysdmessage.h" -#include - -using namespace icsneo; -using namespace icsneo::Disk; - -optional NeoMemoryDiskReadDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report, - uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) { - static std::shared_ptr NeoMemorySDRead = std::make_shared(Network::NetID::NeoMemorySDRead); - - if(amount != SectorSize) - return 0; - - if(cachePos != pos || std::chrono::steady_clock::now() > cachedAt + CacheTime) { - // The cache does not have this data, go get it - const uint64_t currentSector = pos / SectorSize; - auto msg = com.waitForMessageSync([¤tSector, &com] { - return com.sendCommand(Command::NeoReadMemory, { - MemoryTypeSD, - uint8_t(currentSector & 0xFF), - uint8_t((currentSector >> 8) & 0xFF), - uint8_t((currentSector >> 16) & 0xFF), - uint8_t((currentSector >> 24) & 0xFF), - uint8_t(SectorSize & 0xFF), - uint8_t((SectorSize >> 8) & 0xFF), - uint8_t((SectorSize >> 16) & 0xFF), - uint8_t((SectorSize >> 24) & 0xFF) - }); - }, NeoMemorySDRead, 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 nullopt; - } - - memcpy(cache.data(), sdmsg->data.data(), SectorSize); - cachedAt = std::chrono::steady_clock::now(); - cachePos = pos; - } - - memcpy(into, cache.data(), SectorSize); - return SectorSize; -} \ No newline at end of file diff --git a/include/icsneo/communication/command.h b/include/icsneo/communication/command.h index 406623e..eafdaf2 100644 --- a/include/icsneo/communication/command.h +++ b/include/icsneo/communication/command.h @@ -9,6 +9,7 @@ enum class Command : uint8_t { EnableNetworkCommunication = 0x07, EnableNetworkCommunicationEx = 0x08, NeoReadMemory = 0x40, + NeoWriteMemory = 0x41, RequestSerialNumber = 0xA1, GetMainVersion = 0xA3, // Previously known as RED_CMD_APP_VERSION_REQ SetSettings = 0xA4, // Previously known as RED_CMD_SET_BAUD_REQ, follow up with SaveSettings to write to EEPROM diff --git a/include/icsneo/communication/network.h b/include/icsneo/communication/network.h index 4909c73..4b9868a 100644 --- a/include/icsneo/communication/network.h +++ b/include/icsneo/communication/network.h @@ -43,7 +43,7 @@ public: RED_DFLASH_READ = 22, NeoMemorySDRead = 23, // Response from NeoMemory (MemoryTypeSD) CAN_ERRBITS = 24, - RED_DFLASH_WRITE_DONE = 25, + NeoMemoryWriteDone = 25, RED_WAVE_CAN1_LOGICAL = 26, RED_WAVE_CAN2_LOGICAL = 27, RED_WAVE_LIN1_LOGICAL = 28, @@ -275,6 +275,7 @@ public: case NetID::LogicalDiskInfo: case NetID::EthPHYControl: case NetID::NeoMemorySDRead: + case NetID::NeoMemoryWriteDone: return Type::Internal; case NetID::Invalid: case NetID::Any: @@ -367,8 +368,8 @@ public: return "NeoMemorySDRead"; case NetID::CAN_ERRBITS: return "CAN_ERRBITS"; - case NetID::RED_DFLASH_WRITE_DONE: - return "RED_DFLASH_WRITE_DONE"; + case NetID::NeoMemoryWriteDone: + return "NeoMemoryWriteDone"; case NetID::RED_WAVE_CAN1_LOGICAL: return "RED_WAVE_CAN1_LOGICAL"; case NetID::RED_WAVE_CAN2_LOGICAL: @@ -835,9 +836,9 @@ private: #define ICSNEO_NETID_RED_EXT_MEMORYREAD 20 #define ICSNEO_NETID_RED_INT_MEMORYREAD 21 #define ICSNEO_NETID_RED_DFLASH_READ 22 -#define ICSNEO_NETID_RED_SDCARD_READ 23 +#define ICSNEO_NETID_NEOMEMORY_SD_READ 23 #define ICSNEO_NETID_CAN_ERRBITS 24 -#define ICSNEO_NETID_RED_DFLASH_WRITE_DONE 25 +#define ICSNEO_NETID_NEOMEMORY_WRITE_DONE 25 #define ICSNEO_NETID_RED_WAVE_CAN1_LOGICAL 26 #define ICSNEO_NETID_RED_WAVE_CAN2_LOGICAL 27 #define ICSNEO_NETID_RED_WAVE_LIN1_LOGICAL 28 diff --git a/include/icsneo/device/tree/neovired2/neovired2.h b/include/icsneo/device/tree/neovired2/neovired2.h index 22ab7ef..1bca6ca 100644 --- a/include/icsneo/device/tree/neovired2/neovired2.h +++ b/include/icsneo/device/tree/neovired2/neovired2.h @@ -5,6 +5,7 @@ #include "icsneo/device/devicetype.h" #include "icsneo/platform/pcap.h" #include "icsneo/disk/extextractordiskreaddriver.h" +#include "icsneo/disk/neomemorydiskdriver.h" #include "icsneo/device/tree/neovired2/neovired2settings.h" namespace icsneo { @@ -68,7 +69,7 @@ public: protected: NeoVIRED2(neodevice_t neodevice) : Device(neodevice) { - initialize(); + initialize(); getWritableNeoDevice().type = DEVICE_TYPE; productId = PRODUCT_ID; } diff --git a/include/icsneo/device/tree/plasion/neoviion.h b/include/icsneo/device/tree/plasion/neoviion.h index fbc8d55..1a92b1e 100644 --- a/include/icsneo/device/tree/plasion/neoviion.h +++ b/include/icsneo/device/tree/plasion/neoviion.h @@ -7,6 +7,7 @@ #include "icsneo/device/devicetype.h" #include "icsneo/platform/ftdi.h" #include "icsneo/disk/plasiondiskreaddriver.h" +#include "icsneo/disk/neomemorydiskdriver.h" namespace icsneo { @@ -25,7 +26,7 @@ public: private: NeoVIION(neodevice_t neodevice) : Plasion(neodevice) { - initialize(); + initialize(); getWritableNeoDevice().type = DEVICE_TYPE; productId = PRODUCT_ID; } diff --git a/include/icsneo/disk/neomemorydiskreaddriver.h b/include/icsneo/disk/neomemorydiskdriver.h similarity index 63% rename from include/icsneo/disk/neomemorydiskreaddriver.h rename to include/icsneo/disk/neomemorydiskdriver.h index 6c3cc37..086a17e 100644 --- a/include/icsneo/disk/neomemorydiskreaddriver.h +++ b/include/icsneo/disk/neomemorydiskdriver.h @@ -1,9 +1,10 @@ -#ifndef __NEOMEMORYDISKREADDRIVER_H__ -#define __NEOMEMORYDISKREADDRIVER_H__ +#ifndef __NEOMEMORYDISKDRIVER_H__ +#define __NEOMEMORYDISKDRIVER_H__ #ifdef __cplusplus #include "icsneo/disk/diskreaddriver.h" +#include "icsneo/disk/diskwritedriver.h" #include #include @@ -12,11 +13,11 @@ namespace icsneo { namespace Disk { /** - * A disk read driver which uses the neoMemory command to read from the disk + * A disk driver which uses the neoMemory command to read from or write to the disk * - * This can only request reads by sector, so it will be very slow, but is likely supported by any device with a disk + * This can only make requests per sector, so it will be very slow, but is likely supported by any device with a disk */ -class NeoMemoryDiskReadDriver : public ReadDriver { +class NeoMemoryDiskDriver : public ReadDriver, public WriteDriver { public: std::pair getBlockSizeBounds() const override { static_assert(SectorSize <= std::numeric_limits::max(), "Incorrect sector size"); @@ -36,6 +37,9 @@ private: optional readLogicalDiskAligned(Communication& com, device_eventhandler_t report, uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) override; + + optional writeLogicalDiskAligned(Communication& com, device_eventhandler_t report, + uint64_t pos, const uint8_t* atomicBuf, const uint8_t* from, uint64_t amount, std::chrono::milliseconds timeout) override; }; } // namespace Disk @@ -43,4 +47,4 @@ private: } // namespace icsneo #endif // __cplusplus -#endif // __NEOMEMORYDISKREADDRIVER_H__ \ No newline at end of file +#endif // __NEOMEMORYDISKDRIVER_H__ \ No newline at end of file