diff --git a/CMakeLists.txt b/CMakeLists.txt index bcb2dce..32165d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,6 +154,7 @@ set(SRC_FILES disk/nulldiskdriver.cpp disk/neomemorydiskreaddriver.cpp disk/plasiondiskreaddriver.cpp + disk/fat.cpp ${PLATFORM_SRC} ) diff --git a/device/device.cpp b/device/device.cpp index 5d00b73..67758a2 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -4,6 +4,7 @@ #include "icsneo/communication/command.h" #include "icsneo/device/extensions/deviceextension.h" #include "icsneo/platform/optional.h" +#include "icsneo/disk/fat.h" #include #include #include @@ -532,6 +533,20 @@ optional Device::getLogicalDiskSize() { return info->getReportedSize(); } +optional Device::getVSAOffsetInLogicalDisk() { + if(!isOpen()) { + report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error); + return nullopt; + } + + if (diskReadDriver->getAccess() == Disk::Access::VSA || diskReadDriver->getAccess() == Disk::Access::None) + return 0ull; + + return Disk::FindVSAInFAT([this](uint64_t pos, uint8_t *into, uint64_t amount) { + return readLogicalDisk(pos, into, amount); + }); +} + optional Device::getDigitalIO(IO type, size_t number /* = 1 */) { if(number == 0) { // Start counting from 1 report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); diff --git a/disk/fat.cpp b/disk/fat.cpp new file mode 100644 index 0000000..564a881 --- /dev/null +++ b/disk/fat.cpp @@ -0,0 +1,48 @@ +#include "icsneo/disk/fat.h" +#include "icsneo/disk/diskdriver.h" +#include "ff.h" +#include "diskio.h" +#include + +using namespace icsneo; + +// The FAT driver can only be accessed by one caller at a time, since it relies on globals +static std::mutex fatDriverMutex; +static std::function< optional(uint64_t pos, uint8_t* into, uint64_t amount) > diskReadFn; + +extern "C" DRESULT disk_read(BYTE, BYTE* buff, LBA_t sector, UINT count) { + static_assert(Disk::SectorSize == 512, "FatFs expects 512 byte sectors"); + + const uint64_t expected = count * uint64_t(Disk::SectorSize); + const auto res = diskReadFn(sector * uint64_t(Disk::SectorSize), buff, expected); + if (!res.has_value()) + return RES_NOTRDY; + return res == expected ? RES_OK : RES_ERROR; +} + +extern "C" DSTATUS disk_initialize(BYTE) { + return RES_OK; +} + +extern "C" DSTATUS disk_status(BYTE) { + return RES_OK; +} + +static uint64_t ClusterToSector(const FATFS& fs, DWORD cluster) { + return fs.database + (LBA_t)fs.csize * (cluster - 2); +} + +optional Disk::FindVSAInFAT(std::function< optional(uint64_t pos, uint8_t* into, uint64_t amount) > diskRead) { + std::lock_guard lk(fatDriverMutex); + diskReadFn = diskRead; + + FATFS fs = {}; + if (f_mount(&fs, "", 0) != FR_OK) + return nullopt; + + FIL logData = {}; + if (f_open(&logData, "0:\\LOG_DATA.VSA", FA_READ) != FR_OK) + return nullopt; + + return ClusterToSector(fs, logData.obj.sclust) * uint64_t(Disk::SectorSize); +} \ No newline at end of file diff --git a/include/icsneo/device/device.h b/include/icsneo/device/device.h index d5997a6..e61332d 100644 --- a/include/icsneo/device/device.h +++ b/include/icsneo/device/device.h @@ -198,6 +198,18 @@ public: */ optional getLogicalDiskSize(); + /** + * Get the offset to the VSA filesystem within the logical disk, represented + * in bytes. + * + * This method is synchronous and consacts the device for the latest status + * if necessary. + * + * `icsneo::nullopt` will be returned if the device does not respond in a + * timely manner, or if the disk is disconnected/improperly configured. + */ + optional getVSAOffsetInLogicalDisk(); + /** * Retrieve the number of Ethernet (DoIP) Activation lines present * on this device. diff --git a/include/icsneo/disk/fat.h b/include/icsneo/disk/fat.h new file mode 100644 index 0000000..c462448 --- /dev/null +++ b/include/icsneo/disk/fat.h @@ -0,0 +1,22 @@ +#ifndef __FAT_H__ +#define __FAT_H__ + +#ifdef __cplusplus + +#include "icsneo/platform/optional.h" +#include +#include + +namespace icsneo { + +namespace Disk { + +optional FindVSAInFAT(std::function< optional(uint64_t pos, uint8_t* into, uint64_t amount) > diskRead); + +} // namespace Disk + +} // namespace icsneo + +#endif // __cplusplus + +#endif // __FAT_H__ \ No newline at end of file