diff --git a/device/device.cpp b/device/device.cpp index 9ad6888..7c8e508 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -510,7 +510,33 @@ bool Device::stopScript() } bool Device::uploadCoremini(std::unique_ptr&& stream, Disk::MemoryType memType) { + + if(!stream || stream->bad()) { + report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error); + return false; + } + std::vector bin(std::istreambuf_iterator(*stream), {}); // Read the whole stream + + if(bin.size() < 4) { + report(APIEvent::Type::BufferInsufficient, APIEvent::Severity::Error); + return false; + } + + uint16_t scriptVersion = *(uint16_t*)(&bin[2]); // Third and fourth byte are version number stored in little endian + + auto scriptStatus = getScriptStatus(); + + if(!scriptStatus) { + return false; // Already added an API error + } + + if(scriptStatus->coreminiVersion != scriptVersion) { + // Version on device and script are not the same + report(APIEvent::Type::CoreminiUploadVersionMismatch, APIEvent::Severity::Error); + return false; + } + auto startAddress = getCoreminiStartAddress(memType); if(!startAddress) { return false; @@ -531,29 +557,12 @@ bool Device::uploadCoremini(std::unique_ptr&& stream, Disk::Memory return false; } - if(!stream || stream->bad()) { - report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error); + if(!clearScript(memType)) { return false; } - std::vector bin(std::istreambuf_iterator(*stream), {}); // Read the whole stream - if(bin.size() < 4) { - report(APIEvent::Type::BufferInsufficient, APIEvent::Severity::Error); - return false; - } - - uint16_t scriptVersion = *(uint16_t*)(&bin[2]); // Third and fourth byte are version number stored in little endian - - auto scriptStatus = getScriptStatus(); - - if(!scriptStatus) { - return false; // Already added an API error - } - - if(scriptStatus->coreminiVersion != scriptVersion) { - // Version on device and script are not the same - report(APIEvent::Type::CoreminiUploadVersionMismatch, APIEvent::Severity::Error); + if(!eraseScriptMemory(memType, static_cast(bin.size()))) { return false; } @@ -563,7 +572,7 @@ bool Device::uploadCoremini(std::unique_ptr&& stream, Disk::Memory return false; // Already added an API error } - if(*numWritten == 0) { + if(*numWritten != static_cast(bin.size())) { report(APIEvent::Type::FailedToWrite, APIEvent::Severity::Error); return false; // Failed to write } @@ -571,16 +580,60 @@ bool Device::uploadCoremini(std::unique_ptr&& stream, Disk::Memory return true; } -bool Device::clearScript() +bool Device::eraseScriptMemory(Disk::MemoryType memType, uint64_t amount) { + static std::shared_ptr NeoEraseDone = std::make_shared(Network::NetID::NeoMemoryWriteDone); + + auto startAddress = getCoreminiStartAddress(memType); + if(!startAddress) { + return false; + } + + if(memType != Disk::MemoryType::Flash) { + // Only need to erase on flash + return true; + } + + std::vector arguments(9, 0); + + uint32_t numWords = static_cast(amount / 2); + + arguments[0] = static_cast(memType); + *reinterpret_cast(&arguments[1]) = static_cast(*startAddress / 512); + *reinterpret_cast(&arguments[5])= numWords; + + auto msg = com->waitForMessageSync([this, &arguments] { + return com->sendCommand(Command::NeoEraseMemory, arguments); + }, NeoEraseDone, std::chrono::milliseconds(3000)); + + if(!msg) { + return false; + } + + return true; +} + +bool Device::clearScript(Disk::MemoryType memType) { if(!stopScript()) return false; + + + auto startAddress = getCoreminiStartAddress(memType); + if(!startAddress) { + return false; + } std::vector clearData(512, 0xCD); - uint64_t ScriptLocation = 0; //We only support a coremini in an SDCard, which is at the very beginning of the card - auto written = writeLogicalDisk(ScriptLocation, clearData.data(), clearData.size()); + auto written = writeLogicalDisk(*startAddress, clearData.data(), clearData.size(), std::chrono::milliseconds(2000), memType); - return written > 0; + if(!written) { + return false; + } + if(*written == 0) { + return false; + } + + return true; } bool Device::transmit(std::shared_ptr frame) { diff --git a/disk/neomemorydiskdriver.cpp b/disk/neomemorydiskdriver.cpp index 601db17..b5474cb 100644 --- a/disk/neomemorydiskdriver.cpp +++ b/disk/neomemorydiskdriver.cpp @@ -18,18 +18,20 @@ std::optional NeoMemoryDiskDriver::readLogicalDiskAligned(Communicatio const uint64_t currentSector = pos / SectorSize; const uint8_t memLocation = (uint8_t)memType; + + uint64_t numWords = amount / 2; - auto msg = com.waitForMessageSync([¤tSector, &memLocation, &com] { + auto msg = com.waitForMessageSync([¤tSector, &memLocation, &com, &numWords] { return com.sendCommand(Command::NeoReadMemory, { memLocation, 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) + uint8_t(numWords & 0xFF), + uint8_t((numWords >> 8) & 0xFF), + uint8_t((numWords >> 16) & 0xFF), + uint8_t((numWords >> 24) & 0xFF) }); }, NeoMemorySDRead, timeout); @@ -60,15 +62,17 @@ std::optional NeoMemoryDiskDriver::writeLogicalDiskAligned(Communicati const uint64_t currentSector = pos / SectorSize; const uint8_t memLocation = (uint8_t)memType; - auto msg = com.waitForMessageSync([¤tSector, &memLocation, &com, from, amount] { + uint64_t numWords = amount / 2; + + auto msg = com.waitForMessageSync([¤tSector, &memLocation, &com, from, amount, &numWords] { std::vector command = { memLocation, 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(numWords & 0xFF), + uint8_t((numWords >> 8) & 0xFF), }; command.insert(command.end(), from, from + amount); return com.sendCommand(Command::NeoWriteMemory, command); diff --git a/examples/cpp/coremini/src/coremini.cpp b/examples/cpp/coremini/src/coremini.cpp index 08f5b69..21c9884 100644 --- a/examples/cpp/coremini/src/coremini.cpp +++ b/examples/cpp/coremini/src/coremini.cpp @@ -1,5 +1,5 @@ // Usage: -// ./libicsneocpp-coremini [DEVICE_SERIAL] [COREMINI_SCRIPT_PATH] +// ./libicsneocpp-coremini [DEVICE_SERIAL] [COREMINI_SCRIPT_PATH] [FLASH | SD] #include @@ -8,14 +8,14 @@ void displayUsage() { std::cout << "Usage:\n"; - std::cout << "./libicsneocpp-coremini [DEVICE_SERIAL] [COREMINI_SCRIPT_PATH]\n"; + std::cout << "./libicsneocpp-coremini [DEVICE_SERIAL] [COREMINI_SCRIPT_PATH] [FLASH | SD]\n"; } int main(int argc, char** argv) { std::vector arguments(argv, argv + argc); - if(arguments.size() != 3) { + if(arguments.size() != 4) { displayUsage(); return EXIT_FAILURE; } @@ -50,14 +50,25 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } - if (!device->uploadCoremini(std::make_unique(arguments[2], std::ios::binary), icsneo::Disk::MemoryType::Flash)) - { + std::string memTypeString = arguments[3]; + + icsneo::Disk::MemoryType type; + if(memTypeString == "FLASH") { + type = icsneo::Disk::MemoryType::Flash; + } else if(memTypeString == "SD") { + type = icsneo::Disk::MemoryType::SD; + } else { + std::cout << "Incorrect memory type option" << std::endl; + displayUsage(); + return EXIT_FAILURE; + } + + if (!device->uploadCoremini(std::make_unique(arguments[2], std::ios::binary), type)) { std::cout << "Failed to upload coremini" << std::endl; std::cout << icsneo::GetLastError() << std::endl; } - if (!device->startScript(icsneo::Disk::MemoryType::Flash)) - { + if (!device->startScript(type)) { std::cout << "Failed to start script" << std::endl; std::cout << icsneo::GetLastError() << std::endl; } diff --git a/include/icsneo/communication/command.h b/include/icsneo/communication/command.h index d74d7e1..141bb14 100644 --- a/include/icsneo/communication/command.h +++ b/include/icsneo/communication/command.h @@ -31,6 +31,7 @@ enum class Command : uint8_t { GetVBattReq = 0xDF, // Previously known as RED_CMD_VBATT_REQUEST ScriptStatus = 0xE0, // Previously known as RED_CMD_SCRIPT_STATUS MiscControl = 0xE7, + NeoEraseMemory = 0xEA, // Previously known as RED_CMD_ERASE_MEMORY Extended = 0xF0, // Previously known as RED_CMD_EXT_COMM ExtendedData = 0xF2, // Previously known as RED_CMD_EXTENDED_DATA FlexRayControl = 0xF3, diff --git a/include/icsneo/device/device.h b/include/icsneo/device/device.h index 8951164..7aecc83 100644 --- a/include/icsneo/device/device.h +++ b/include/icsneo/device/device.h @@ -148,9 +148,11 @@ public: int8_t prepareScriptLoad(); bool startScript(Disk::MemoryType memType = Disk::MemoryType::SD); bool stopScript(); - bool clearScript(); + bool clearScript(Disk::MemoryType memType = Disk::MemoryType::SD); bool uploadCoremini(std::unique_ptr&& stream, Disk::MemoryType memType = Disk::MemoryType::SD); + bool eraseScriptMemory(Disk::MemoryType memType, uint64_t amount); + virtual std::optional getCoreminiStartAddressFlash() const { return std::nullopt; } diff --git a/include/icsneo/device/tree/neovifire2/neovifire2.h b/include/icsneo/device/tree/neovifire2/neovifire2.h index 0d9d258..794220e 100644 --- a/include/icsneo/device/tree/neovifire2/neovifire2.h +++ b/include/icsneo/device/tree/neovifire2/neovifire2.h @@ -6,7 +6,7 @@ #include "icsneo/device/device.h" #include "icsneo/device/devicetype.h" #include "icsneo/device/tree/neovifire2/neovifire2settings.h" - +#include "icsneo/disk/neomemorydiskdriver.h" namespace icsneo { class NeoVIFIRE2 : public Device { @@ -89,7 +89,7 @@ public: protected: NeoVIFIRE2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { - initialize(makeDriver); + initialize(makeDriver); } void setupSettings(IDeviceSettings& ssettings) override {