Disk: Refactor ExtExtractorDiskReadDriver
Reading disk data is currently accomplished by redirecting the raw input stream for the duration of the acquisition, during which no other operation can be carried out. This change moves disk data reading into the packetizer so the familiar request/reply with message filters can be used. To accomplish this the deprecated ISOPIC network type was dropped because the two messages share this network ID. Also fixes live data packet lengths which were off-by-one.136-add-android-support
parent
508013baf4
commit
0c436621a0
|
|
@ -15,6 +15,7 @@
|
|||
#include "icsneo/communication/message/mdiomessage.h"
|
||||
#include "icsneo/communication/message/extendeddatamessage.h"
|
||||
#include "icsneo/communication/message/livedatamessage.h"
|
||||
#include "icsneo/communication/message/diskdatamessage.h"
|
||||
#include "icsneo/communication/command.h"
|
||||
#include "icsneo/device/device.h"
|
||||
#include "icsneo/communication/packet/canpacket.h"
|
||||
|
|
@ -429,6 +430,10 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
|||
}
|
||||
return true;
|
||||
}
|
||||
case Network::NetID::DiskData: {
|
||||
result = std::make_shared<DiskDataMessage>(std::move(packet->data));
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,12 +104,8 @@ bool HardwareLiveDataPacket::EncodeFromMessage(LiveDataMessage& message, std::ve
|
|||
return false;
|
||||
}
|
||||
}
|
||||
// Send as a long message without setting the NetID to RED first
|
||||
// Size in long format is the size of the entire packet
|
||||
// So +1 for AA header, +1 for short format header (only netID)
|
||||
// +2 for long format size, +1 for the Main51 extended command
|
||||
// +2 for the extended subcommand, +2 for the payload length
|
||||
uint16_t fullSize = static_cast<uint16_t>(1 + sizeof(ExtendedCommandHeader) + payloadSize);
|
||||
// +1 for AA, another +1 for firmware nuance
|
||||
uint16_t fullSize = static_cast<uint16_t>(1 + sizeof(ExtendedCommandHeader) + payloadSize) + 1;
|
||||
|
||||
ExtendedCommandHeader* header = reinterpret_cast<ExtendedCommandHeader*>(bytestream.data());
|
||||
if(!header) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "icsneo/communication/packetizer.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace icsneo;
|
||||
|
|
@ -49,44 +48,97 @@ bool Packetizer::input(const std::vector<uint8_t>& inputBytes) {
|
|||
haveEnoughData = false;
|
||||
break;
|
||||
}
|
||||
|
||||
packetLength = bytes[1] >> 4 & 0xF;
|
||||
packet.network = Network(bytes[1] & 0xF); // Lower nibble of the second byte is the network ID
|
||||
|
||||
packetLength = bytes[1] >> 4 & 0xf; // Upper nibble of the second byte denotes the packet length
|
||||
packet.network = Network(bytes[1] & 0xf); // Lower nibble of the second byte is the network ID
|
||||
if(packetLength == 0) { // A length of zero denotes a long style packet
|
||||
if(packetLength == 0) {
|
||||
state = ReadState::ParseLongStylePacketHeader;
|
||||
checksum = false;
|
||||
headerSize = 6;
|
||||
} else {
|
||||
state = ReadState::GetData;
|
||||
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
|
||||
break;
|
||||
} else if(packetLength == 0xA && packet.network == Network::NetID::DiskData) {
|
||||
state = ReadState::ParseDiskDataHeader;
|
||||
break;
|
||||
}
|
||||
|
||||
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
|
||||
currentIndex++;
|
||||
state = ReadState::GetData;
|
||||
break;
|
||||
case ReadState::ParseLongStylePacketHeader:
|
||||
if(bytes.size() < 6) {
|
||||
haveEnoughData = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
packetLength = bytes[2]; // Long packets have a little endian length on bytes 3 and 4
|
||||
packetLength |= bytes[3] << 8;
|
||||
packet.network = Network(((bytes[5] << 8) | bytes[4]), false); // Long packets have their netid stored as little endian on bytes 5 and 6. Devices never send actual VNET IDs so we must not perform ID expansion here.
|
||||
currentIndex += 4;
|
||||
|
||||
/* Long packets can't have a length less than 6, because that would indicate a negative payload size.
|
||||
* Unlike the short packet length, the long packet length encompasses everything from the 0xAA to the
|
||||
* end of the payload. The short packet length, for reference, only encompasses the length of the actual
|
||||
* payload, and not the header or checksum.
|
||||
*/
|
||||
* Unlike the short packet length, the long packet length encompasses everything from the 0xAA to the
|
||||
* end of the payload. The short packet length, for reference, only encompasses the length of the actual
|
||||
* payload, and not the header or checksum.
|
||||
*/
|
||||
if(packetLength < 6 || packetLength > 4000) {
|
||||
bytes.pop_front();
|
||||
EventManager::GetInstance().add(APIEvent::Type::FailedToRead, APIEvent::Severity::Error);
|
||||
state = ReadState::SearchForHeader;
|
||||
} else {
|
||||
state = ReadState::GetData;
|
||||
break;
|
||||
}
|
||||
|
||||
checksum = false;
|
||||
headerSize = 6;
|
||||
currentIndex += 5;
|
||||
state = ReadState::GetData;
|
||||
break;
|
||||
case ReadState::ParseDiskDataHeader:
|
||||
if(bytes.size() < 3) {
|
||||
haveEnoughData = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(bytes[2] != 0xAA) {
|
||||
bytes.pop_front();
|
||||
state = ReadState::SearchForHeader;
|
||||
break;
|
||||
}
|
||||
|
||||
if(bytes.size() < 4) {
|
||||
haveEnoughData = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(bytes[3] != 0x55) {
|
||||
bytes.pop_front();
|
||||
state = ReadState::SearchForHeader;
|
||||
break;
|
||||
}
|
||||
|
||||
if(bytes.size() < 5) {
|
||||
haveEnoughData = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(bytes[4] != 0x55) {
|
||||
bytes.pop_front();
|
||||
state = ReadState::SearchForHeader;
|
||||
break;
|
||||
}
|
||||
|
||||
if(bytes.size() < 7) {
|
||||
haveEnoughData = false;
|
||||
break;
|
||||
}
|
||||
|
||||
packetLength = bytes[5] | (bytes[6] << 8);
|
||||
|
||||
checksum = false;
|
||||
headerSize = 7;
|
||||
packetLength += headerSize;
|
||||
currentIndex += 6;
|
||||
state = ReadState::GetData;
|
||||
break;
|
||||
case ReadState::GetData:
|
||||
// We do not include the checksum in packetLength so it doesn't get copied into the payload buffer
|
||||
|
|
@ -98,7 +150,7 @@ bool Packetizer::input(const std::vector<uint8_t>& inputBytes) {
|
|||
packet.data.clear();
|
||||
if(packetLength > 0)
|
||||
packet.data.resize(packetLength - headerSize);
|
||||
|
||||
|
||||
auto i = 0;
|
||||
while(currentIndex < packetLength)
|
||||
packet.data[i++] = bytes[currentIndex++];
|
||||
|
|
@ -109,12 +161,16 @@ bool Packetizer::input(const std::vector<uint8_t>& inputBytes) {
|
|||
processedPackets.push_back(std::make_shared<Packet>(packet));
|
||||
for (auto a = 0; a < packetLength; a++)
|
||||
bytes.pop_front();
|
||||
|
||||
if(packet.network == Network::NetID::DiskData && (packetLength - headerSize) % 2 == 0) {
|
||||
bytes.pop_front();
|
||||
}
|
||||
} else {
|
||||
if(gotGoodPackets) // Don't complain unless we've already gotten a good packet, in case we started in the middle of a stream
|
||||
report(APIEvent::Type::PacketChecksumError, APIEvent::Severity::Error);
|
||||
bytes.pop_front(); // Drop the first byte so it doesn't get picked up again
|
||||
}
|
||||
|
||||
|
||||
// Reset for the next packet
|
||||
currentIndex = 0;
|
||||
state = ReadState::SearchForHeader;
|
||||
|
|
|
|||
|
|
@ -248,9 +248,16 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
|
|||
|
||||
MessageFilter filter;
|
||||
filter.includeInternalInAny = true;
|
||||
std::atomic<bool> receivedMessage{false};
|
||||
auto messageReceivedCallbackID = com->addMessageCallback(std::make_shared<MessageCallback>(filter, [&receivedMessage](std::shared_ptr<Message> message) {
|
||||
receivedMessage = true;
|
||||
|
||||
std::condition_variable heartbeatCV;
|
||||
std::mutex receivedMessageMutex;
|
||||
bool receivedMessage = false;
|
||||
auto messageReceivedCallbackID = com->addMessageCallback(std::make_shared<MessageCallback>(filter, [&](std::shared_ptr<Message> message) {
|
||||
{
|
||||
std::scoped_lock<std::mutex> lk(receivedMessageMutex);
|
||||
receivedMessage = true;
|
||||
}
|
||||
heartbeatCV.notify_all();
|
||||
}));
|
||||
|
||||
// Give the device time to get situated
|
||||
|
|
@ -263,6 +270,7 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
|
|||
while(!stopHeartbeatThread) {
|
||||
// Wait for 110ms for a possible heartbeat
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(110));
|
||||
std::unique_lock<std::mutex> recvLk(receivedMessageMutex);
|
||||
if(receivedMessage) {
|
||||
receivedMessage = false;
|
||||
} else {
|
||||
|
|
@ -281,12 +289,8 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
|
|||
// No heartbeat received, request a status
|
||||
com->sendCommand(Command::RequestStatusUpdate);
|
||||
|
||||
// Wait until we either received the message or reach max wait time
|
||||
for (uint32_t sleepTime = 0; sleepTime < 3500 && !receivedMessage; sleepTime += 50)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
// Check if we got a message, and if not, if settings are being applied
|
||||
if(receivedMessage) {
|
||||
if(heartbeatCV.wait_for(recvLk, std::chrono::milliseconds(3500), [&](){ return receivedMessage; })) {
|
||||
receivedMessage = false;
|
||||
} else {
|
||||
if(!stopHeartbeatThread && !isDisconnected()) {
|
||||
|
|
@ -448,8 +452,6 @@ int8_t Device::prepareScriptLoad() {
|
|||
|
||||
static std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::CoreMiniPreLoad);
|
||||
|
||||
std::lock_guard<std::mutex> lg(diskLock);
|
||||
|
||||
if(!com->sendCommand(Command::CoreMiniPreload))
|
||||
return false;
|
||||
|
||||
|
|
@ -477,8 +479,6 @@ bool Device::startScript(Disk::MemoryType memType)
|
|||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lg(diskLock);
|
||||
|
||||
uint8_t location = static_cast<uint8_t>(memType);
|
||||
auto generic = com->sendCommand(Command::LoadCoreMini, location);
|
||||
|
||||
|
|
@ -498,8 +498,6 @@ bool Device::stopScript()
|
|||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lg(diskLock);
|
||||
|
||||
auto generic = com->sendCommand(Command::ClearCoreMini);
|
||||
|
||||
if(!generic)
|
||||
|
|
@ -663,7 +661,7 @@ std::optional<uint64_t> Device::readLogicalDisk(uint64_t pos, uint8_t* into, uin
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lk(diskLock);
|
||||
std::lock_guard<std::mutex> lk(diskMutex);
|
||||
|
||||
if(diskReadDriver->getAccess() == Disk::Access::EntireCard && diskWriteDriver->getAccess() == Disk::Access::VSA) {
|
||||
// We have mismatched drivers, we need to add an offset to the diskReadDriver
|
||||
|
|
@ -678,9 +676,6 @@ std::optional<uint64_t> Device::readLogicalDisk(uint64_t pos, uint8_t* into, uin
|
|||
diskReadDriver->setVSAOffset(*offset);
|
||||
}
|
||||
|
||||
// This is needed for certain read drivers which take over the communication stream
|
||||
const auto lifetime = suppressDisconnects();
|
||||
|
||||
return diskReadDriver->readLogicalDisk(*com, report, pos, into, amount, timeout, memType);
|
||||
}
|
||||
|
||||
|
|
@ -695,7 +690,6 @@ std::optional<uint64_t> Device::writeLogicalDisk(uint64_t pos, const uint8_t* fr
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lk(diskLock);
|
||||
return diskWriteDriver->writeLogicalDisk(*com, report, *diskReadDriver, pos, from, amount, timeout, memType);
|
||||
}
|
||||
|
||||
|
|
@ -705,9 +699,6 @@ std::optional<bool> Device::isLogicalDiskConnected() {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
// This doesn't *really* make sense here but because the disk read redirects the parser until it is done, we'll lock this
|
||||
// just to avoid the timeout.
|
||||
std::lock_guard<std::mutex> lg(diskLock);
|
||||
const auto info = com->getLogicalDiskInfoSync();
|
||||
if (!info) {
|
||||
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
|
||||
|
|
@ -723,9 +714,6 @@ std::optional<uint64_t> Device::getLogicalDiskSize() {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
// This doesn't *really* make sense here but because the disk read redirects the parser until it is done, we'll lock this
|
||||
// just to avoid the timeout.
|
||||
std::lock_guard<std::mutex> lg(diskLock);
|
||||
const auto info = com->getLogicalDiskInfoSync();
|
||||
if (!info) {
|
||||
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
|
||||
|
|
@ -746,8 +734,6 @@ std::optional<uint64_t> Device::getVSAOffsetInLogicalDisk() {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lk(diskLock);
|
||||
|
||||
if (diskReadDriver->getAccess() == Disk::Access::VSA || diskReadDriver->getAccess() == Disk::Access::None)
|
||||
return 0ull;
|
||||
|
||||
|
|
@ -972,9 +958,6 @@ std::optional<double> Device::getAnalogIO(IO type, size_t number /* = 1 */) {
|
|||
void Device::wiviThreadBody() {
|
||||
std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::WiVICommandResponse);
|
||||
std::unique_lock<std::mutex> lk(wiviMutex);
|
||||
// Disk access commands can
|
||||
std::unique_lock<std::mutex> dl(diskLock);
|
||||
dl.unlock();
|
||||
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
|
||||
|
||||
bool first = true;
|
||||
|
|
@ -985,11 +968,9 @@ void Device::wiviThreadBody() {
|
|||
stopWiVIcv.wait_for(lk, std::chrono::seconds(3));
|
||||
|
||||
// Use the command GetAll to get a WiVI::Info structure from the device
|
||||
dl.lock();
|
||||
const auto generic = com->waitForMessageSync([this]() {
|
||||
return com->sendCommand(Command::WiVICommand, WiVI::CommandPacket::GetAll::Encode());
|
||||
}, filter);
|
||||
dl.unlock();
|
||||
|
||||
if(!generic || generic->type != Message::Type::WiVICommandResponse) {
|
||||
report(APIEvent::Type::WiVIStackRefreshFailed, APIEvent::Severity::Error);
|
||||
|
|
@ -1067,11 +1048,9 @@ void Device::wiviThreadBody() {
|
|||
}
|
||||
|
||||
if(!clearMasks.empty()) {
|
||||
dl.lock();
|
||||
const auto clearMasksGenericResp = com->waitForMessageSync([this, &clearMasks]() {
|
||||
return com->sendCommand(Command::WiVICommand, WiVI::CommandPacket::ClearUploads::Encode(clearMasks));
|
||||
}, filter);
|
||||
dl.unlock();
|
||||
|
||||
if(!clearMasksGenericResp
|
||||
|| clearMasksGenericResp->type != Message::Type::WiVICommandResponse
|
||||
|
|
@ -1214,7 +1193,6 @@ std::optional<bool> Device::isSleepRequested() const {
|
|||
static std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::WiVICommandResponse);
|
||||
// Hold this lock so the WiVI stack doesn't issue a WiVICommand at the same time as us
|
||||
std::lock_guard<std::mutex> lk(wiviMutex);
|
||||
std::lock_guard<std::mutex> lg(diskLock);
|
||||
const auto generic = com->waitForMessageSync([this]() {
|
||||
// VSSAL sets bit0 to indicate that it's waiting to sleep, then
|
||||
// it waits for Wireless neoVI to acknowledge by clearing it.
|
||||
|
|
@ -1252,7 +1230,6 @@ bool Device::allowSleep(bool remoteWakeup) {
|
|||
static std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::WiVICommandResponse);
|
||||
// Hold this lock so the WiVI stack doesn't issue a WiVICommand at the same time as us
|
||||
std::lock_guard<std::mutex> lk(wiviMutex);
|
||||
std::lock_guard<std::mutex> lg(diskLock);
|
||||
const auto generic = com->waitForMessageSync([this, remoteWakeup]() {
|
||||
// VSSAL sets bit0 to indicate that it's waiting to sleep, then
|
||||
// it waits for Wireless neoVI to acknowledge by clearing it.
|
||||
|
|
@ -1425,7 +1402,6 @@ std::shared_ptr<ScriptStatusMessage> Device::getScriptStatus() const
|
|||
{
|
||||
static std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::ScriptStatus);
|
||||
|
||||
std::lock_guard<std::mutex> lg(diskLock);
|
||||
const auto generic = com->waitForMessageSync([this]() {
|
||||
return com->sendCommand(Command::ScriptStatus);
|
||||
}, filter, std::chrono::milliseconds(3000));
|
||||
|
|
@ -1686,7 +1662,6 @@ std::optional<bool> Device::SetCollectionUploaded(uint32_t collectionEntryByteAd
|
|||
(uint8_t)((collectionEntryByteAddress >> 16) & 0xFF),
|
||||
(uint8_t)((collectionEntryByteAddress >> 24) & 0xFF)});
|
||||
|
||||
std::lock_guard<std::mutex> lg(diskLock);
|
||||
std::shared_ptr<Message> response = com->waitForMessageSync(
|
||||
[this, args](){ return com->sendCommand(ExtendedCommand::SetUploadedFlag, args); },
|
||||
std::make_shared<MessageFilter>(Message::Type::ExtendedResponse), timeout);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
#include "icsneo/disk/extextractordiskreaddriver.h"
|
||||
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
|
||||
#include "icsneo/communication/multichannelcommunication.h"
|
||||
#include "icsneo/api/lifetime.h"
|
||||
#include <cstring>
|
||||
#include "icsneo/communication/message/diskdatamessage.h"
|
||||
|
||||
//#define ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
|
|
@ -46,144 +43,33 @@ std::optional<uint64_t> ExtExtractorDiskReadDriver::attemptReadLogicalDiskAligne
|
|||
if (largeSectorCount != uint64_t(sectorCount))
|
||||
return std::nullopt;
|
||||
|
||||
std::mutex m;
|
||||
std::condition_variable cv;
|
||||
uint16_t receiving = 0; // How much are we about to get before another header or completion
|
||||
uint64_t received = 0;
|
||||
uint16_t receivedCurrent = 0;
|
||||
size_t skipping = 0;
|
||||
std::vector<uint8_t> header;
|
||||
std::unique_lock<std::mutex> lk(m);
|
||||
bool error = !com.redirectRead([&](std::vector<uint8_t>&& data) {
|
||||
std::unique_lock<std::mutex> lk2(m);
|
||||
if(error) {
|
||||
lk2.unlock();
|
||||
cv.notify_all();
|
||||
return;
|
||||
}
|
||||
std::mutex mutex;
|
||||
uint8_t* intoOffset = into;
|
||||
int64_t remaining = amount;
|
||||
bool complete = false;
|
||||
|
||||
if(skipping > data.size()) {
|
||||
skipping -= data.size();
|
||||
return;
|
||||
}
|
||||
size_t offset = skipping;
|
||||
skipping = 0;
|
||||
while(offset < data.size()) {
|
||||
size_t left = data.size() - offset;
|
||||
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
std::cout << "Going to process " << left << " bytes" << std::endl;
|
||||
#endif
|
||||
if(header.size() != HeaderLength) {
|
||||
if(header.empty() && left && data[offset] != 0xaa) {
|
||||
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
std::cout << "Incorrect header " << int(data[offset]) << ' ' << int(offset) << std::endl;
|
||||
#endif
|
||||
error = true;
|
||||
lk2.unlock();
|
||||
cv.notify_all();
|
||||
return;
|
||||
const auto handle = com.addMessageCallback(std::make_shared<MessageCallback>([&](std::shared_ptr<Message> message) {
|
||||
if(remaining > 0) {
|
||||
const auto diskdata = std::static_pointer_cast<DiskDataMessage>(message);
|
||||
|
||||
const auto& data = diskdata->data;
|
||||
std::copy(data.data(), data.data() + data.size(), intoOffset);
|
||||
|
||||
intoOffset += data.size();
|
||||
remaining -= data.size();
|
||||
|
||||
if(remaining == 0) {
|
||||
{
|
||||
std::scoped_lock<std::mutex> lk(mutex);
|
||||
complete = true;
|
||||
}
|
||||
|
||||
// Did we get a correct header and at least one byte of data?
|
||||
const auto begin = data.begin() + offset;
|
||||
int32_t headerLeft = int32_t(HeaderLength - header.size());
|
||||
if(int32_t(left) < headerLeft) {
|
||||
// Not enough data here, grab what header we can and continue
|
||||
header.insert(header.end(), begin, data.end());
|
||||
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
std::cout << "Got " << int(left) << " bytes of header at " << offset << " (incomplete " <<
|
||||
header.size() << ')' << std::endl;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
header.insert(header.end(), begin, begin + headerLeft);
|
||||
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
std::cout << "Got " << int(headerLeft) << " bytes of header at " << offset << " (complete " <<
|
||||
header.size() << ')' << std::endl;
|
||||
#endif
|
||||
offset += headerLeft;
|
||||
|
||||
if(header[1] == uint8_t(Network::NetID::RED)) {
|
||||
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
std::cout << "Got extended response " << int(offset) << std::endl;
|
||||
#endif
|
||||
// This is the extended command response, not all devices send this
|
||||
// If we got it, we need to figure out how much more data to ignore
|
||||
uint16_t length = (header[2] + (header[3] << 8));
|
||||
// Try for another header after this, regardless how much we choose
|
||||
// to skip and how we skip it
|
||||
header.clear();
|
||||
if(length <= 6) {
|
||||
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
std::cout << "Incorrect extended response length " << int(length) << ' ' << int(offset) << std::endl;
|
||||
#endif
|
||||
error = true;
|
||||
lk2.unlock();
|
||||
cv.notify_all();
|
||||
return;
|
||||
}
|
||||
length -= 7;
|
||||
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
std::cout << "Skipping " << int(length) << ' ' << int(left) << std::endl;
|
||||
#endif
|
||||
if(left < length) {
|
||||
skipping = length - left;
|
||||
return;
|
||||
}
|
||||
offset += length;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The device tells us how much it's sending us before the next header
|
||||
receiving = (header[5] | (header[6] << 8));
|
||||
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
std::cout << "Started packet of size " << receiving << " bytes" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
left = data.size() - offset;
|
||||
auto count = uint16_t(std::min<uint64_t>(std::min<uint64_t>(receiving - receivedCurrent, left), amount - received));
|
||||
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
std::cout << "With " << int(left) << " bytes " << int(offset) << std::endl;
|
||||
#endif
|
||||
memcpy(into + received, data.data() + offset, count);
|
||||
received += count;
|
||||
receivedCurrent += count;
|
||||
offset += count;
|
||||
|
||||
if(amount == received) {
|
||||
if(receivedCurrent % 2 == 0)
|
||||
offset++;
|
||||
header.clear(); // Now we will need another header
|
||||
lk2.unlock();
|
||||
cv.notify_all();
|
||||
lk2.lock();
|
||||
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
std::cout << "Finished!" << std::endl;
|
||||
#endif
|
||||
}
|
||||
else if(receivedCurrent == receiving) {
|
||||
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
std::cout << "Got " << count << " bytes, " << receivedCurrent << " byte packet " << received <<
|
||||
" complete of " << amount << std::endl;
|
||||
#endif
|
||||
if(receivedCurrent % 2 == 0)
|
||||
offset++;
|
||||
header.clear(); // Now we will need another header
|
||||
receivedCurrent = 0;
|
||||
} else {
|
||||
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||
std::cout << "Got " << count << " bytes, incomplete (of " << receiving << " bytes)" << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
});
|
||||
Lifetime clearRedirect([&com, &lk] { lk.unlock(); com.clearRedirectRead(); });
|
||||
}, std::make_shared<MessageFilter>(Network::NetID::DiskData)));
|
||||
|
||||
if(error)
|
||||
return std::nullopt;
|
||||
|
||||
error = !com.sendCommand(ExtendedCommand::Extract, {
|
||||
if(!com.sendCommand(ExtendedCommand::Extract, {
|
||||
uint8_t(sector & 0xff),
|
||||
uint8_t((sector >> 8) & 0xff),
|
||||
uint8_t((sector >> 16) & 0xff),
|
||||
|
|
@ -196,13 +82,16 @@ std::optional<uint64_t> ExtExtractorDiskReadDriver::attemptReadLogicalDiskAligne
|
|||
uint8_t((sectorCount >> 8) & 0xff),
|
||||
uint8_t((sectorCount >> 16) & 0xff),
|
||||
uint8_t((sectorCount >> 24) & 0xff),
|
||||
});
|
||||
if(error)
|
||||
})) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
const auto successful = cv.wait_for(lk, timeout, [&](){ return complete; });
|
||||
com.removeMessageCallback(handle);
|
||||
|
||||
if(!successful)
|
||||
return std::nullopt;
|
||||
|
||||
bool hitTimeout = !cv.wait_for(lk, timeout, [&]() { return error || amount == received; });
|
||||
if(hitTimeout || error)
|
||||
return std::nullopt;
|
||||
|
||||
return amount;
|
||||
return amount - remaining;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3511,16 +3511,6 @@ SWIGEXPORT int SWIGSTDCALL CSharp_ICSNEO_NETID_ISO_get() {
|
|||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_ICSNEO_NETID_ISOPIC_get() {
|
||||
int jresult ;
|
||||
int result;
|
||||
|
||||
result = (int)(10);
|
||||
jresult = result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_ICSNEO_NETID_MAIN51_get() {
|
||||
int jresult ;
|
||||
int result;
|
||||
|
|
|
|||
|
|
@ -325,7 +325,6 @@ public class icsneocsharp {
|
|||
public static readonly int ICSNEO_NETID_AUX = icsneocsharpPINVOKE.ICSNEO_NETID_AUX_get();
|
||||
public static readonly int ICSNEO_NETID_J1850VPW = icsneocsharpPINVOKE.ICSNEO_NETID_J1850VPW_get();
|
||||
public static readonly int ICSNEO_NETID_ISO = icsneocsharpPINVOKE.ICSNEO_NETID_ISO_get();
|
||||
public static readonly int ICSNEO_NETID_ISOPIC = icsneocsharpPINVOKE.ICSNEO_NETID_ISOPIC_get();
|
||||
public static readonly int ICSNEO_NETID_MAIN51 = icsneocsharpPINVOKE.ICSNEO_NETID_MAIN51_get();
|
||||
public static readonly int ICSNEO_NETID_RED = icsneocsharpPINVOKE.ICSNEO_NETID_RED_get();
|
||||
public static readonly int ICSNEO_NETID_SCI = icsneocsharpPINVOKE.ICSNEO_NETID_SCI_get();
|
||||
|
|
|
|||
|
|
@ -1017,9 +1017,6 @@ class icsneocsharpPINVOKE {
|
|||
[global::System.Runtime.InteropServices.DllImport("icsneocsharp.dll", EntryPoint="CSharp_ICSNEO_NETID_ISO_get")]
|
||||
public static extern int ICSNEO_NETID_ISO_get();
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("icsneocsharp.dll", EntryPoint="CSharp_ICSNEO_NETID_ISOPIC_get")]
|
||||
public static extern int ICSNEO_NETID_ISOPIC_get();
|
||||
|
||||
[global::System.Runtime.InteropServices.DllImport("icsneocsharp.dll", EntryPoint="CSharp_ICSNEO_NETID_MAIN51_get")]
|
||||
public static extern int ICSNEO_NETID_MAIN51_get();
|
||||
|
||||
|
|
|
|||
|
|
@ -5506,18 +5506,6 @@ SWIGEXPORT jint JNICALL Java_icsneojavaJNI_ICSNEO_1NETID_1ISO_1get(JNIEnv *jenv,
|
|||
}
|
||||
|
||||
|
||||
SWIGEXPORT jint JNICALL Java_icsneojavaJNI_ICSNEO_1NETID_1ISOPIC_1get(JNIEnv *jenv, jclass jcls) {
|
||||
jint jresult = 0 ;
|
||||
int result;
|
||||
|
||||
(void)jenv;
|
||||
(void)jcls;
|
||||
result = (int)(10);
|
||||
jresult = (jint)result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT jint JNICALL Java_icsneojavaJNI_ICSNEO_1NETID_1MAIN51_1get(JNIEnv *jenv, jclass jcls) {
|
||||
jint jresult = 0 ;
|
||||
int result;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ public interface icsneojavaConstants {
|
|||
public final static int ICSNEO_NETID_AUX = icsneojavaJNI.ICSNEO_NETID_AUX_get();
|
||||
public final static int ICSNEO_NETID_J1850VPW = icsneojavaJNI.ICSNEO_NETID_J1850VPW_get();
|
||||
public final static int ICSNEO_NETID_ISO = icsneojavaJNI.ICSNEO_NETID_ISO_get();
|
||||
public final static int ICSNEO_NETID_ISOPIC = icsneojavaJNI.ICSNEO_NETID_ISOPIC_get();
|
||||
public final static int ICSNEO_NETID_MAIN51 = icsneojavaJNI.ICSNEO_NETID_MAIN51_get();
|
||||
public final static int ICSNEO_NETID_RED = icsneojavaJNI.ICSNEO_NETID_RED_get();
|
||||
public final static int ICSNEO_NETID_SCI = icsneojavaJNI.ICSNEO_NETID_SCI_get();
|
||||
|
|
|
|||
|
|
@ -283,7 +283,6 @@ public class icsneojavaJNI {
|
|||
public final static native int ICSNEO_NETID_AUX_get();
|
||||
public final static native int ICSNEO_NETID_J1850VPW_get();
|
||||
public final static native int ICSNEO_NETID_ISO_get();
|
||||
public final static native int ICSNEO_NETID_ISOPIC_get();
|
||||
public final static native int ICSNEO_NETID_MAIN51_get();
|
||||
public final static native int ICSNEO_NETID_RED_get();
|
||||
public final static native int ICSNEO_NETID_SCI_get();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef __DISKDATAMESSAGE_H_
|
||||
#define __DISKDATAMESSAGE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/communication/message/message.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
class DiskDataMessage : public RawMessage {
|
||||
public:
|
||||
DiskDataMessage(std::vector<uint8_t>&& d) : RawMessage(Network::NetID::DiskData) {
|
||||
data = std::move(d);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif
|
||||
|
|
@ -34,7 +34,7 @@ public:
|
|||
Aux = 7,
|
||||
J1850VPW = 8,
|
||||
ISO9141 = 9,
|
||||
ISOPIC = 10,
|
||||
DiskData = 10,
|
||||
Main51 = 11,
|
||||
RED = 12,
|
||||
SCI = 13,
|
||||
|
|
@ -342,7 +342,7 @@ public:
|
|||
case 9:
|
||||
return NetID::ISO9141;
|
||||
case 10:
|
||||
return NetID::ISOPIC;
|
||||
return NetID::DiskData;
|
||||
case 11:
|
||||
return NetID::Main51;
|
||||
case 12:
|
||||
|
|
@ -536,6 +536,7 @@ public:
|
|||
case NetID::NeoMemorySDRead:
|
||||
case NetID::NeoMemoryWriteDone:
|
||||
case NetID::RED_GET_RTC:
|
||||
case NetID::DiskData:
|
||||
return Type::Internal;
|
||||
case NetID::Invalid:
|
||||
case NetID::Any:
|
||||
|
|
@ -617,8 +618,8 @@ public:
|
|||
return "J1850 VPW";
|
||||
case NetID::ISO9141:
|
||||
return "ISO 9141";
|
||||
case NetID::ISOPIC:
|
||||
return "ISOPIC";
|
||||
case NetID::DiskData:
|
||||
return "Disk Data";
|
||||
case NetID::Main51:
|
||||
return "Main51";
|
||||
case NetID::RED:
|
||||
|
|
@ -1265,7 +1266,7 @@ private:
|
|||
#define ICSNEO_NETID_AUX 7
|
||||
#define ICSNEO_NETID_J1850VPW 8
|
||||
#define ICSNEO_NETID_ISO9141 9
|
||||
#define ICSNEO_NETID_ISOPIC 10
|
||||
#define ICSNEO_NETID_DISK_DATA 10
|
||||
#define ICSNEO_NETID_MAIN51 11
|
||||
#define ICSNEO_NETID_RED 12
|
||||
#define ICSNEO_NETID_SCI 13
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ private:
|
|||
SearchForHeader,
|
||||
ParseHeader,
|
||||
ParseLongStylePacketHeader,
|
||||
ParseDiskDataHeader,
|
||||
GetData
|
||||
};
|
||||
ReadState state = ReadState::SearchForHeader;
|
||||
|
|
|
|||
|
|
@ -692,7 +692,6 @@ private:
|
|||
std::vector<std::optional<DeviceAppVersion>> versions;
|
||||
std::vector<ComponentVersion> componentVersions;
|
||||
|
||||
mutable std::mutex diskLock;
|
||||
std::unique_ptr<Disk::ReadDriver> diskReadDriver;
|
||||
std::unique_ptr<Disk::WriteDriver> diskWriteDriver;
|
||||
|
||||
|
|
@ -731,6 +730,8 @@ private:
|
|||
std::mutex heartbeatMutex;
|
||||
std::thread heartbeatThread;
|
||||
|
||||
std::mutex diskMutex;
|
||||
|
||||
// Wireless neoVI Stack
|
||||
std::atomic<bool> stopWiVIThread{false};
|
||||
std::condition_variable stopWiVIcv;
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ typedef unsigned __int64 uint64_t;
|
|||
#define NETID_AUX 7
|
||||
#define NETID_JVPW 8
|
||||
#define NETID_ISO 9
|
||||
#define NETID_ISOPIC 10
|
||||
#define NETID_DISK_DATA 10
|
||||
#define NETID_MAIN51 11
|
||||
#define NETID_RED 12
|
||||
#define NETID_SCI 13
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ protected:
|
|||
{
|
||||
0xaa, //start AA
|
||||
0x0B, //netid main51
|
||||
0x2F, 0x00, //size little end 16
|
||||
0x30, 0x00, //size little end 16
|
||||
0xF0, //extended header command
|
||||
0x35, 0x00, //Live data subcommand little 16
|
||||
0x26, 0x00, //extended subcommand size, little 16
|
||||
|
|
@ -68,7 +68,7 @@ protected:
|
|||
{
|
||||
0xaa, //start AA
|
||||
0x0B, //netid main51
|
||||
0x15, 0x00, //size little end 16
|
||||
0x16, 0x00, //size little end 16
|
||||
0xF0, //extended header command
|
||||
0x35, 0x00, //Live data subcommand little 16
|
||||
0x0C, 0x00, //extended subcommand size, little 16
|
||||
|
|
@ -82,7 +82,7 @@ protected:
|
|||
{
|
||||
0xaa, //start AA
|
||||
0x0B, //netid main51
|
||||
0x15, 0x00, //size little end 16
|
||||
0x16, 0x00, //size little end 16
|
||||
0xF0, //extended header command
|
||||
0x35, 0x00, //Live data subcommand little 16
|
||||
0x0C, 0x00, //extended subcommand size, little 16
|
||||
|
|
|
|||
Loading…
Reference in New Issue