Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 46 additions & 5 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class _MyHomePageState extends State<MyHomePage> {
// Services
late final DeviceCommunicationService _deviceService;
late final NetworkService _networkService;
late final DataProcessingService _dataService;
late final DmpDecoderService _dmpDecoder;
late final FileService _fileService;
late final FirmwareUpdateService _firmwareService;

Expand Down Expand Up @@ -176,7 +176,7 @@ class _MyHomePageState extends State<MyHomePage> {
// Initialize services
_deviceService = DeviceCommunicationService();
_networkService = NetworkService();
_dataService = DataProcessingService();
_dmpDecoder = DmpDecoderService();
_fileService = FileService();
_firmwareService = FirmwareUpdateService(_deviceService);

Expand Down Expand Up @@ -301,7 +301,7 @@ class _MyHomePageState extends State<MyHomePage> {
for (final fileResult in successfulFiles) {
if (fileResult.hasData) {
transferBuffer = fileResult.data!;
final dataResult = await _dataService.processTransferBuffer(transferBuffer, unitType);
final dataResult = await _dmpDecoder.processTransferBuffer(transferBuffer, unitType);

if (dataResult.success) {
setState(() {
Expand Down Expand Up @@ -375,7 +375,7 @@ class _MyHomePageState extends State<MyHomePage> {
}

Future<void> _analyzeTransferBuffer() async {
final result = await _dataService.processTransferBuffer(transferBuffer, unitType);
final result = await _dmpDecoder.processTransferBuffer(transferBuffer, unitType);

if (result.success) {
setState(() {
Expand Down Expand Up @@ -533,7 +533,48 @@ class _MyHomePageState extends State<MyHomePage> {

// Export handlers
Future<void> _onSaveDMP() async {
await _handleExportOperation(() => _fileService.saveDMPFileFromSections(sections, unitType));
try {
final result = await _fileService.saveDMPFileFromSections(sections, unitType);

if (result.needsChoice && result.versionAnalysis != null && mounted) {
// Show dialog for mixed version handling
final choice = await MixedVersionDialog.show(context, result.versionAnalysis!);

if (choice == MixedVersionChoice.cancel) {
return;
}

// Get file path
final filePath = await _fileService.getSaveFilePathPublic("DMP", "dmp");
if (filePath == null) {
return;
}

FileResult finalResult;
if (choice == MixedVersionChoice.separate) {
finalResult = await _fileService.saveDMPFileSeparate(result.versionAnalysis!, filePath);
} else {
finalResult = await _fileService.saveDMPFileAsV6(sections.selectedSections, filePath);
}

if (finalResult.success && mounted) {
_showMessage(finalResult.message ?? 'Export completed successfully');
} else if (!finalResult.success && mounted) {
_showErrorMessage(finalResult.error ?? 'Export failed');
}
} else {
// Normal result handling
if (result.success && mounted) {
_showMessage(result.message ?? 'Export completed successfully');
} else if (!result.success && mounted) {
_showErrorMessage(result.error ?? 'Export failed');
}
}
} catch (e) {
if (mounted) {
_showErrorMessage('Export failed: $e');
}
}
}

Future<void> _onExportXLS() async {
Expand Down
120 changes: 120 additions & 0 deletions lib/models/dmp_constants.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/// DMP (Data Memory Package) file format constants
///
/// These constants define the binary structure of MNemo v2 DMP files.
/// See: doc/MNemo DMP File Format - Complete Documentation.md
class DmpConstants {
// Private constructor to prevent instantiation
DmpConstants._();

// ============================================================================
// FILE VERSION MAGIC BYTES (Version 5+)
// ============================================================================

/// Magic byte A for file version header (version 5+)
static const int fileVersionMagicA = 68; // 0x44

/// Magic byte B for file version header (version 5+)
static const int fileVersionMagicB = 89; // 0x59

/// Magic byte C for file version header (version 5+)
static const int fileVersionMagicC = 101; // 0x65

// ============================================================================
// SHOT RECORD MAGIC BYTES (Version 5+)
// ============================================================================

/// Magic byte A for shot record start (version 5+)
static const int shotStartMagicA = 57; // 0x39

/// Magic byte B for shot record start (version 5+)
static const int shotStartMagicB = 67; // 0x43

/// Magic byte C for shot record start (version 5+)
static const int shotStartMagicC = 77; // 0x4D

/// Magic byte A for shot record end (version 5+)
static const int shotEndMagicA = 95; // 0x5F

/// Magic byte B for shot record end (version 5+)
static const int shotEndMagicB = 25; // 0x19

/// Magic byte C for shot record end (version 5+)
static const int shotEndMagicC = 35; // 0x23

// ============================================================================
// LIDAR DATA MAGIC BYTES (Version 6)
// ============================================================================

/// Magic byte A for Lidar data block start (version 6)
static const int lidarStartMagicA = 32; // 0x20 - VOLSTART_VALA

/// Magic byte B for Lidar data block start (version 6)
static const int lidarStartMagicB = 33; // 0x21 - VOLSTART_VALB

/// Magic byte C for Lidar data block start (version 6)
static const int lidarStartMagicC = 34; // 0x22 - VOLSTART_VALC

// ============================================================================
// FORMAT VERSION LIMITS
// ============================================================================

/// Minimum supported DMP file version
static const int minSupportedVersion = 2;

/// Maximum supported DMP file version
static const int maxSupportedVersion = 6;

/// First version with magic byte validation
static const int firstVersionWithMagicBytes = 5;

/// First version with temperature and time data
static const int firstVersionWithTemperature = 3;

/// First version with LRUD passage measurements
static const int firstVersionWithLRUD = 4;

/// First version with optional Lidar data
static const int firstVersionWithLidar = 6;

// ============================================================================
// RECORD SIZES
// ============================================================================

/// Size of section header in bytes
static const int sectionHeaderSize = 13;

/// Size of shot record in bytes (v5+, excluding optional Lidar data)
static const int shotRecordSize = 35;

/// Size of each Lidar point in bytes
static const int lidarPointSize = 6;

// ============================================================================
// VALIDATION HELPERS
// ============================================================================

/// Check if a version number is valid
static bool isValidVersion(int version) {
return version >= minSupportedVersion && version <= maxSupportedVersion;
}

/// Check if a version uses magic bytes
static bool usesMagicBytes(int version) {
return version >= firstVersionWithMagicBytes;
}

/// Check if a version supports temperature data
static bool hasTemperature(int version) {
return version >= firstVersionWithTemperature;
}

/// Check if a version supports LRUD data
static bool hasLRUD(int version) {
return version >= firstVersionWithLRUD;
}

/// Check if a version supports Lidar data
static bool hasLidar(int version) {
return version >= firstVersionWithLidar;
}
}
3 changes: 2 additions & 1 deletion lib/models/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export 'shot.dart';
export 'section.dart';
export 'section_list.dart';
export 'survey_quality.dart';
export 'lidar_data.dart';
export 'lidar_data.dart';
export 'dmp_constants.dart';
Loading