Exemple #1
0
        public void Test_TerrainSwather_SwathExtentTooLarge()
        {
            var siteModel = new SiteModel(StorageMutability.Immutable);
            var machine   = new Machine();
            var grid      = new ServerSubGridTree(siteModel.ID, StorageMutability.Mutable);
            var SiteModelGridAggregator             = new ServerSubGridTree(siteModel.ID, StorageMutability.Mutable);
            var MachineTargetValueChangesAggregator = new ProductionEventLists(siteModel, MachineConsts.kNullInternalSiteModelMachineIndex);
            var processor = new TAGProcessor(siteModel, machine, SiteModelGridAggregator, MachineTargetValueChangesAggregator);

            var fence   = new Fence(new BoundingWorldExtent3D(0, 0, 10000, 2));
            var swather = new TerrainSwather(processor, MachineTargetValueChangesAggregator, siteModel, grid, fence);

            CreateSwathContext(0, 0, 0,
                               10000, 0, 0,
                               0, 2, 0,
                               10000, 2, 0,
                               out SimpleTriangle HeightInterpolator1,
                               out SimpleTriangle HeightInterpolator2,
                               out SimpleTriangle TimeInterpolator1,
                               out SimpleTriangle TimeInterpolator2);

            bool swathResult = swather.PerformSwathing(HeightInterpolator1, HeightInterpolator2, TimeInterpolator1, TimeInterpolator2, false, PassType.Front, MachineSide.None);

            swathResult.Should().BeTrue();
            processor.ProcessedEpochCount.Should().Be(0);
            processor.ProcessedCellPassesCount.Should().Be(0);
        }
Exemple #2
0
        public void Test_TAGProcessor_DoPostProcessFileAction()
        {
            var SiteModel = new SiteModel(StorageMutability.Immutable);
            var Machine   = new Machine();
            var SiteModelGridAggregator             = new ServerSubGridTree(SiteModel.ID, StorageMutability.Mutable);
            var MachineTargetValueChangesAggregator = new ProductionEventLists(SiteModel, MachineConsts.kNullInternalSiteModelMachineIndex);

            TAGProcessor processor = new TAGProcessor(SiteModel, Machine, SiteModelGridAggregator, MachineTargetValueChangesAggregator);

            // Set the state of the processor to emulate the end of processing this TAG file at which point the processor should emit
            // a "Stop recording event". In this instance, the NoGPSModeSet flag will also be true which should trigger emission of
            // a 'NoGPS' GPS mode state event and a 'UTS' positioning technology state event

            DateTime eventDate = DateTime.SpecifyKind(new DateTime(2000, 1, 1, 1, 1, 1), DateTimeKind.Utc);

            // Setting the first data time will create the start event
            processor.DataTime = eventDate;

            DateTime eventDate2 = eventDate.AddMinutes(1);

            processor.DataTime = eventDate2;
            processor.DoPostProcessFileAction(true);

            Assert.True(MachineTargetValueChangesAggregator.GPSModeStateEvents.LastStateValue() == GPSMode.NoGPS &&
                        MachineTargetValueChangesAggregator.GPSModeStateEvents.LastStateDate() == eventDate,
                        "DoPostProcessFileAction did not set GPSMode event");

            Assert.True(MachineTargetValueChangesAggregator.PositioningTechStateEvents.LastStateValue() == PositioningTech.UTS &&
                        MachineTargetValueChangesAggregator.PositioningTechStateEvents.LastStateDate() == eventDate,
                        "DoPostProcessFileAction did not set positioning tech event");

            Assert.True(MachineTargetValueChangesAggregator.StartEndRecordedDataEvents.LastStateValue() == ProductionEventType.EndEvent /*EndRecordedData*/ &&
                        MachineTargetValueChangesAggregator.StartEndRecordedDataEvents.LastStateDate() == eventDate2,
                        "DoPostProcessFileAction did not set end recorded data event");
        }
Exemple #3
0
        public void Test_TAGProcessor_DoEpochStateEvent()
        {
            var processor = new TAGProcessor();

            Action act = () => processor.DoEpochStateEvent(EpochStateEvent.Unknown);

            act.Should().Throw <TRexTAGFileProcessingException>().WithMessage("*Unknown epoch state event type*");
        }
Exemple #4
0
        public void Test_TAGProcessor_Creation()
        {
            var SiteModel = new SiteModel(StorageMutability.Immutable);
            var Machine   = new Machine();
            var SiteModelGridAggregator             = new ServerSubGridTree(SiteModel.ID, StorageMutability.Mutable);
            var MachineTargetValueChangesAggregator = new ProductionEventLists(SiteModel, MachineConsts.kNullInternalSiteModelMachineIndex);

            TAGProcessor processor = new TAGProcessor(SiteModel, Machine, SiteModelGridAggregator, MachineTargetValueChangesAggregator);

            Assert.NotNull(processor);
        }
Exemple #5
0
        public void Test_TAGProcessor_DoEpochPreProcessAction()
        {
            var SiteModel = new SiteModel(StorageMutability.Immutable);
            var Machine   = new Machine();
            var SiteModelGridAggregator             = new ServerSubGridTree(SiteModel.ID, StorageMutability.Mutable);
            var MachineTargetValueChangesAggregator = new ProductionEventLists(SiteModel, MachineConsts.kNullInternalSiteModelMachineIndex);

            TAGProcessor processor = new TAGProcessor(SiteModel, Machine, SiteModelGridAggregator, MachineTargetValueChangesAggregator);

            Assert.True(processor.DoEpochPreProcessAction(), "EpochPreProcessAction returned false in default TAGProcessor state");

            // Current PreProcessAction activity is limited to handling proofing runs. This will be handled by proofing run tests elsewhere
        }
Exemple #6
0
        public void Test_TerrainSwather_Creation()
        {
            var siteModel = new SiteModel(StorageMutability.Immutable);
            var machine   = new Machine();
            var grid      = new ServerSubGridTree(siteModel.ID, StorageMutability.Mutable);
            var fence     = new Fence();
            var SiteModelGridAggregator             = new ServerSubGridTree(siteModel.ID, StorageMutability.Mutable);
            var MachineTargetValueChangesAggregator = new ProductionEventLists(siteModel, MachineConsts.kNullInternalSiteModelMachineIndex);
            var processor = new TAGProcessor(siteModel, machine, SiteModelGridAggregator, MachineTargetValueChangesAggregator);

            var swather = new TerrainSwather(processor, MachineTargetValueChangesAggregator, siteModel, grid, fence);

            Assert.True(swather != null, "TerrainSwather not created as expected");
        }
Exemple #7
0
        /// <summary>
        /// Fill out the local class properties with the information wanted from the TAG file
        /// </summary>
        /// <param name="processor"></param>
        private void SetPublishedState(TAGProcessor processor)
        {
            ProcessedEpochCount    = processor.ProcessedEpochCount;
            ProcessedCellPassCount = processor.ProcessedCellPassesCount;

            // Set the site model's last modified date...
            SiteModel.LastModifiedDate = DateTime.UtcNow;

            //Update latest status for the machine
            Machine.LastKnownX = processor.DataLeft.X;
            Machine.LastKnownY = processor.DataLeft.Y;
            Machine.LastKnownPositionTimeStamp = processor.DataTime;
            Machine.MachineHardwareID          = processor.HardwareID;
            Machine.MachineType = processor.MachineType;
            Machine.Name        = processor.MachineID;
        }
Exemple #8
0
        public void LoadFile()
        {
            using var stream = new FileStream(FILENAME, FileMode.Open, FileAccess.Read);
            var file = new VolvoEarthworksCSVReader(stream);

            var siteModel = new SiteModel(StorageMutability.Immutable);
            var machine   = new Machine();
            var siteModelGridAggregator             = new ServerSubGridTree(siteModel.ID, StorageMutability.Mutable);
            var machineTargetValueChangesAggregator = new ProductionEventLists(siteModel, MachineConsts.kNullInternalSiteModelMachineIndex);

            var processor = new TAGProcessor(siteModel, machine, siteModelGridAggregator, machineTargetValueChangesAggregator);

            file.Read(null, processor);

            processor.ProcessedEpochCount.Should().Be(19325);
            siteModelGridAggregator.CountLeafSubGridsInMemory().Should().Be(11);
        }
Exemple #9
0
        public void Test_TAGProcessor_TestZeroValuesInvalid()
        {
            var          SiteModel = new SiteModel(StorageMutability.Immutable);
            var          Machine   = new Machine();
            var          SiteModelGridAggregator             = new ServerSubGridTree(SiteModel.ID, StorageMutability.Mutable);
            var          MachineTargetValueChangesAggregator = new ProductionEventLists(SiteModel, MachineConsts.kNullInternalSiteModelMachineIndex);
            TAGProcessor processor = new TAGProcessor(SiteModel, Machine, SiteModelGridAggregator, MachineTargetValueChangesAggregator);

            Assert.True(processor.ICMDPValues.GetLatest() == CellPassConsts.NullMDP, "MDP Initial value incorrect");
            Assert.True(processor.ICCCVValues.GetLatest() == CellPassConsts.NullCCV, "CCV Initial value incorrect");
            Assert.True(processor.ICCCAValues.GetLatest() == CellPassConsts.NullCCA, "CCA Initial value incorrect");
            processor.SetICMDPValue(0);
            processor.SetICCCVValue(0);
            processor.SetICCCAValue(0);
            Assert.True(processor.ICMDPValues.GetLatest() == CellPassConsts.NullMDP, "Zero should not be a valid for MDP");
            Assert.True(processor.ICCCVValues.GetLatest() == CellPassConsts.NullCCV, "Zero should not be a valid for CCV");
            Assert.True(processor.ICCCAValues.GetLatest() == CellPassConsts.NullCCA, "Zero should not be a valid for CCA");
        }
Exemple #10
0
        public void Test_TAGProcessor_ProcessEpochContext_WithValidPosition()
        {
            var SiteModel = new SiteModel(StorageMutability.Immutable);

            SiteModel.IgnoreInvalidPositions = false;

            var Machine = new Machine();
            var SiteModelGridAggregator             = new ServerSubGridTree(SiteModel.ID, StorageMutability.Mutable);
            var MachineTargetValueChangesAggregator = new ProductionEventLists(SiteModel, MachineConsts.kNullInternalSiteModelMachineIndex);

            TAGProcessor processor = new TAGProcessor(SiteModel, Machine, SiteModelGridAggregator, MachineTargetValueChangesAggregator);

            // Set the blade left and right tip locations to a trivial epoch, the epoch and do it again to trigger a swathing scan, then
            // check to see if it generated anything!

            Fence interpolationFence = new Fence();

            interpolationFence.SetRectangleFence(0, 0, 1, 1);

            DateTime StartTime = DateTime.SpecifyKind(new DateTime(2000, 1, 1, 1, 1, 1), DateTimeKind.Utc);

            processor.DataLeft  = new XYZ(0, 0, 5);
            processor.DataRight = new XYZ(1, 0, 5);
            processor.DataTime  = StartTime;

            Assert.True(processor.ProcessEpochContext(), "ProcessEpochContext returned false in default TAGProcessor state (1)");

            DateTime EndTime = DateTime.SpecifyKind(new DateTime(2000, 1, 1, 1, 1, 3), DateTimeKind.Utc);

            processor.DataLeft  = new XYZ(0, 1, 5);
            processor.DataRight = new XYZ(1, 1, 5);
            processor.DataTime  = EndTime;

            Assert.True(processor.ProcessEpochContext(), "ProcessEpochContext returned false in default TAGProcessor state (2)");

            Assert.Equal(9, processor.ProcessedCellPassesCount);

            Assert.Equal(2, processor.ProcessedEpochCount);
        }
Exemple #11
0
        public void Test_TAGProcessor_ProcessEpochContext_WithoutValidTimestamp()
        {
            var SiteModel = new SiteModel(StorageMutability.Immutable);

            SiteModel.IgnoreInvalidPositions = false;

            var Machine = new Machine();
            var SiteModelGridAggregator             = new ServerSubGridTree(SiteModel.ID, StorageMutability.Mutable);
            var MachineTargetValueChangesAggregator = new ProductionEventLists(SiteModel, MachineConsts.kNullInternalSiteModelMachineIndex);

            TAGProcessor processor = new TAGProcessor(SiteModel, Machine, SiteModelGridAggregator, MachineTargetValueChangesAggregator);

            // Set the blade left and right tip locations to a trivial epoch, the epoch and do it again to trigger a swathing scan, then
            // check to see if it generated anything!

            Fence interpolationFence = new Fence();

            interpolationFence.SetRectangleFence(0, 0, 1, 1);
            processor.DataLeft  = new XYZ(0, 0, 5);
            processor.DataRight = new XYZ(1, 0, 5);

            Assert.False(processor.ProcessEpochContext(), "ProcessEpochContext returned true without a valid epoch timestamp");
        }
Exemple #12
0
        public void Test_TerrainSwather_PerformSwathing()
        {
            var siteModel = new SiteModel(StorageMutability.Immutable);
            var machine   = new VSS.TRex.Machines.Machine();
            var grid      = new ServerSubGridTree(siteModel.ID, StorageMutability.Mutable);
            var SiteModelGridAggregator             = new ServerSubGridTree(siteModel.ID, StorageMutability.Mutable);
            var MachineTargetValueChangesAggregator = new ProductionEventLists(siteModel, MachineConsts.kNullInternalSiteModelMachineIndex);
            var processor = new TAGProcessor(siteModel, machine, SiteModelGridAggregator, MachineTargetValueChangesAggregator);

            var fence = new Fence();

            fence.SetRectangleFence(0, 0, 10, 2);

            TerrainSwather swather = new TerrainSwather(processor, MachineTargetValueChangesAggregator, siteModel, grid, fence);

            CreateSwathContext(0, 0, 0,
                               10, 0, 0,
                               0, 2, 0,
                               10, 2, 0,
                               out SimpleTriangle HeightInterpolator1,
                               out SimpleTriangle HeightInterpolator2,
                               out SimpleTriangle TimeInterpolator1,
                               out SimpleTriangle TimeInterpolator2);

            // Compute swath with full cell pass on the front (blade) measurement location
            bool swathResult = swather.PerformSwathing(HeightInterpolator1, HeightInterpolator2, TimeInterpolator1, TimeInterpolator2, false, PassType.Front, MachineSide.None);

            // Did the swathing operation succeed?
            Assert.True(swathResult, "Perform swathing failed");

            // Did it produce the expected set of swathed cells?
            Assert.Equal(1, grid.Root.CountChildren());

            // Computation of the latest pass information which aids locating cells with non-null values
            try
            {
                IStorageProxy storageProxy = StorageProxy.Instance(StorageMutability.Mutable);
                grid.Root.ScanSubGrids(grid.FullCellExtent(), x =>
                {
                    ((IServerLeafSubGrid)x).ComputeLatestPassInformation(true, storageProxy);
                    return(true);
                });
            }
            catch (Exception E)
            {
                Assert.False(true, $"Exception {E} occured computing latest cell information");
            }

            grid.CalculateIndexOfCellContainingPosition(grid.CellSize / 2, grid.CellSize / 2, out int _, out int _);

            int nonNullCellCount = 0;

            try
            {
                grid.Root.ScanSubGrids(grid.FullCellExtent(), x =>
                {
                    nonNullCellCount += ((IServerLeafSubGrid)x).CountNonNullCells();
                    return(true);
                });
            }
            catch (Exception e)
            {
                Assert.False(true, $"Exception {e} occured counting non-null cells");
            }

            Assert.Equal(174, nonNullCellCount);

            // Todo: Iterate over the cells and confirm their content is as expected
        }
Exemple #13
0
        /// <summary>
        /// Execute the conversion operation on the TAG file, returning a boolean success result.
        /// Sets up local state detailing the pre-scan fields retrieved from the TAG file
        /// </summary>
        public bool ExecuteLegacyTAGFile(string filename, Stream tagData, Guid assetUid, bool isJohnDoe)
        {
            Log.LogInformation($"In {nameof(ExecuteLegacyTAGFile)}: reading file {filename} for asset {assetUid}, JohnDoe: {isJohnDoe}");

            ReadResult = TAGReadResult.NoError;
            List <UTMCoordPointPair> aCSBladePositions    = null;
            List <UTMCoordPointPair> ACSRearAxlePositions = null;
            List <UTMCoordPointPair> ACSTrackPositions    = null;
            List <UTMCoordPointPair> ACSWheelPositions    = null;

            try
            {
                Processor?.Dispose();

                // Locate the machine in the local set of machines, adding one if necessary
                Machine = Machines.Locate(assetUid, isJohnDoe);

                var machineType       = MachineType.Unknown;
                var machineHardwareId = string.Empty;
                var machineId         = string.Empty;

                //Prescan to get all relevant information necessary for processing the tag file. e.g. Machinetype for swather, Type of coordinate system (ACS)
                var tagFilePreScan = new TAGFilePreScan();
                tagFilePreScan.Execute(tagData);
                tagData.Position = 0; // reset
                if (tagFilePreScan.ReadResult == TAGReadResult.NoError)
                {
                    machineType           = tagFilePreScan.MachineType; // used in creation of swather
                    machineHardwareId     = tagFilePreScan.HardwareID;
                    machineId             = tagFilePreScan.MachineID;
                    IsUTMCoordinateSystem = !tagFilePreScan.IsCSIBCoordSystemTypeOnly; // do we need to convert UTM coordinates to project coordinates
                    if (IsUTMCoordinateSystem && tagFilePreScan.ProcessedEpochCount > 0)
                    {
                        Log.LogInformation($"{nameof(ExecuteLegacyTAGFile)}: ACS coordinate system detected. {filename}");
                        aCSBladePositions    = new List <UTMCoordPointPair>();
                        ACSRearAxlePositions = new List <UTMCoordPointPair>();
                        ACSTrackPositions    = new List <UTMCoordPointPair>();
                        ACSWheelPositions    = new List <UTMCoordPointPair>();
                        if (!CollectAndConvertBladePostions(_targetSiteModel, ref tagData, ref aCSBladePositions, ref ACSRearAxlePositions, ref ACSTrackPositions, ref ACSWheelPositions))
                        {
                            Log.LogError($"{nameof(ExecuteLegacyTAGFile)}: Failed to collect and convert blade positions for tagfile processing with ACS. TAG FILE:{filename}");
                            ReadResult = TAGReadResult.CoordinateConversionFailure;
                            return(false);
                        }
                    }
                }
                else
                {
                    Log.LogError($"Unsuccessful prescan of tagfile. {tagFilePreScan.ReadResult}");
                    return(false);
                }

                if (Machine == null)
                {
                    // Now we know more about the machine have another go finding it
                    Machine = Machines.Locate(assetUid, machineId, isJohnDoe);
                }

                if (Machine == null)
                {
                    Log.LogDebug($"Creating new machine in common converter for AssetUid = {assetUid}, JohnDoe = {isJohnDoe}, machineId = {machineId}, machineHardwareId = {machineHardwareId}");

                    Machine = Machines.CreateNew(machineId, machineHardwareId, machineType, DeviceTypeEnum.MANUALDEVICE, isJohnDoe, assetUid);
                }

                if (Machine.MachineType == MachineType.Unknown && machineType != MachineType.Unknown)
                {
                    Machine.MachineType = machineType;
                }

                var holdMachineType = Machine.MachineType;

                // Locate the aggregator, adding one if necessary
                var machineTargetValueChangesAggregator = MachinesTargetValueChangesAggregator[Machine.InternalSiteModelMachineIndex] as ProductionEventLists;
                if (machineTargetValueChangesAggregator == null)
                {
                    machineTargetValueChangesAggregator = new ProductionEventLists(SiteModel, Machine.InternalSiteModelMachineIndex);
                    MachinesTargetValueChangesAggregator.Add(machineTargetValueChangesAggregator);
                }

                Processor = new TAGProcessor(SiteModel, Machine, SiteModelGridAggregator, machineTargetValueChangesAggregator);

                // If ACS coordinate system populate converted UTM coordinates
                if (IsUTMCoordinateSystem && tagFilePreScan.ProcessedEpochCount > 0)
                {
                    if (aCSBladePositions != null && aCSBladePositions.Count > 0)
                    {
                        Processor.ConvertedBladePositions.AddRange(aCSBladePositions);
                    }
                    if (ACSRearAxlePositions != null && ACSRearAxlePositions.Count > 0)
                    {
                        Processor.ConvertedRearAxlePositions.AddRange(ACSRearAxlePositions);
                    }
                    if (ACSTrackPositions != null && ACSTrackPositions.Count > 0)
                    {
                        Processor.ConvertedTrackPositions.AddRange(ACSTrackPositions);
                    }
                    if (ACSWheelPositions != null && ACSWheelPositions.Count > 0)
                    {
                        Processor.ConvertedWheelPositions.AddRange(ACSWheelPositions);
                    }
                }

                var sink = new TAGValueSink(Processor);
                using (var reader = new TAGReader(tagData))
                {
                    var tagFile = new TAGFile();

                    ReadResult = tagFile.Read(reader, sink);

                    // Notify the processor that all reading operations have completed for the file
                    Processor.DoPostProcessFileAction(ReadResult == TAGReadResult.NoError);

                    SetPublishedState(Processor);
                    Machine.MachineType = holdMachineType;

                    if (ReadResult != TAGReadResult.NoError)
                    {
                        return(false);
                    }
                }
            }
            catch (Exception e) // make sure any exception is trapped to return correct response to caller
            {
                Log.LogError(e, "Exception occurred while converting a TAG file");
                return(false);
            }

            return(true);
        }
Exemple #14
0
        /// <summary>
        /// Execute the conversion operation on the Volvo earthworks CSV file
        /// NOTE: This is a POC implementation and does not support some behaviours in the legacy TAG file ingest pathway
        /// </summary>
        public bool ExecuteVolvoEarthworksCSVFile(string filename, Stream tagData, Guid assetUid, bool isJohnDoe)
        {
            ReadResult = TAGReadResult.NoError;

            Log.LogInformation($"In {nameof(ExecuteVolvoEarthworksCSVFile)}: reading file {filename} for asset {assetUid}, JohnDoe: {isJohnDoe}");

            try
            {
                var fileDescriptor = new VolvoEarthworksFileNameDescriptor(filename);

                Processor?.Dispose();

                // Locate the machine in the local set of machines, adding one if necessary
                Machine = Machines.Locate(assetUid, true /*isJohnDoe - hard code Volvo machines to be John Does for POC*/);

                var machineType       = MachineType.Unknown;
                var machineHardwareId = fileDescriptor.MachineID;
                var machineId         = fileDescriptor.MachineID;

                if (Machine == null)
                {
                    Log.LogDebug($"Creating new machine in common converter for AssetUid = {assetUid}, JohnDoe = {isJohnDoe}, machineId = {machineId}, machineHardwareId = {machineHardwareId}");

                    Machine = Machines.CreateNew(machineId, machineHardwareId, machineType, DeviceTypeEnum.MANUALDEVICE, isJohnDoe, assetUid);
                }

                var holdMachineType = Machine.MachineType;

                // Locate the aggregator, adding one if necessary
                var machineTargetValueChangesAggregator = MachinesTargetValueChangesAggregator[Machine.InternalSiteModelMachineIndex] as ProductionEventLists;
                if (machineTargetValueChangesAggregator == null)
                {
                    machineTargetValueChangesAggregator = new ProductionEventLists(SiteModel, Machine.InternalSiteModelMachineIndex);
                    MachinesTargetValueChangesAggregator.Add(machineTargetValueChangesAggregator);
                }

                Processor = new TAGProcessor(SiteModel, Machine, SiteModelGridAggregator, machineTargetValueChangesAggregator);

                var sink   = new TAGValueSink(Processor);
                var reader = new VolvoEarthworksCSVReader(tagData);

                ReadResult = reader.Read(sink, Processor);

                // Notify the processor that all reading operations have completed for the file
                Processor.DoPostProcessFileAction(ReadResult == TAGReadResult.NoError);

                SetPublishedState(Processor);
                Machine.MachineType = holdMachineType;

                if (ReadResult != TAGReadResult.NoError)
                {
                    return(false);
                }
            }
            catch (Exception e) // make sure any exception is trapped to return correct response to caller
            {
                Log.LogError(e, "Exception occurred while converting a Volvo CSV file");
                return(false);
            }

            return(true);
        }
Exemple #15
0
        /// <summary>
        /// Reads the context of a Volvo earthworks CSV file using the provided sink to send data to
        /// Note: LastEDV value is not handled as it has no corresponding value in TRex
        /// </summary>
        public TAGReadResult Read(TAGValueSinkBase sink, TAGProcessor processor)
        {
            using var streamReader = new StreamReader(_stream, Encoding.ASCII);

            var headerLine  = streamReader.ReadLine();
            var headerIndex = 0;

            _headerLocations = headerLine.Split(',').Select(x => new KeyValuePair <string, int>(x, headerIndex++)).ToDictionary(k => k.Key, v => v.Value);

            // Read all remaining lines into an array for easy access
            var lines = ReadLines(streamReader).ToList();

            var swather = new VolvoEarthworksCSVGridSwather(processor,
                                                            processor.MachineTargetValueChangesAggregator,
                                                            processor.SiteModel,
                                                            processor.SiteModelGridAggregator,
                                                            null)
            {
                ProcessedEpochNumber = processor.ProcessedEpochCount
            };

            var currentTime = DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc);

            //var firstDataTime =
            // For each line, locate the TRex cell that fall within the cell and add a cell pass for it
            lines.ForEach(line =>
            {
                var cellPass = ParseLine(line);

                if (!cellPass.lineParsedOK)
                {
                    // Each cell is parsed independently, so we can short circuit processing if a line did not parse
                    return;
                }

                processor.DataTime = DateTime.SpecifyKind(cellPass.Time, DateTimeKind.Utc);

                // There is no RMV in the CSV file - set on ground to be true all the time.
                processor.SetOnGround(OnGroundState.YesLegacy);

                // Default Volvo machine to MC024 sensor returning CMV values
                // TODO: understand if this is a special sensor for Volvo
                // TODO: understand meaning of the ICMVType field
                processor.ICSensorType = CompactionSensorType.MC024;

                // TODO: Understand the relationship of Volvo CMV value to internal CMV value
                processor.SetICCCVValue((short)Math.Round(cellPass.LastCMV));

                processor.MachineType = VolvoEarthworksCSVRecord.MachineTypeFromString(cellPass.Machine);

                if (processor.MachineType == MachineType.Unknown)
                {
                    _log.LogDebug($"Machine type name {cellPass.Machine} generated an unknown machine type");
                }

                // Add the events for this line
                if (currentTime < processor.DataTime)
                {
                    // Fill in the machine events for this epoch
                    processor.Design = cellPass.DesignName;
                }

                // Convert mph to cs/s. 44.704 is the magic mph to cm/s conversion factor
                var speedInCentimetersPerSecond = (int)Math.Round(cellPass.Speed_mph * 44.704);
                processor.SetICMachineSpeedValue(speedInCentimetersPerSecond);

                processor.ICPassTargetValue = (ushort)cellPass.TargetPassCount;
                processor.ValidPosition     = cellPass.ValidPos ? (byte)1 : (byte)0;

                processor.ICLayerIDValue = (ushort)cellPass.Lift;

                processor.SetICFrequency((ushort)cellPass.LastFreq_Hz);
                processor.SetICAmplitude(cellPass.LastAmp_mm == -1000 ? CellPassConsts.NullAmplitude : (ushort)Math.Round(cellPass.LastAmp_mm * 100));

                processor.ICTargetLiftThickness = (float)(cellPass.TargThickness_FT / 3.048);
                processor.ICGear = VolvoEarthworksCSVRecord.MachineGearFromString(cellPass.MachineGear);

                if (processor.ICGear == MachineGear.Null)
                {
                    _log.LogDebug($"Machine gear name {cellPass.MachineGear} generated a null machine gear");
                }

                processor.SetICTemperatureValue((ushort)cellPass.LastTemp_f);
                processor.ICMode = (byte)((cellPass.VibeState == "On" ? 1 : 0) << ICModeFlags.IC_TEMPERATURE_VIBRATION_STATE_SHIFT);

                // Add the cell pass for this line.
                // Note: Half pass is hardwired to false, and pass type is hardwired to front drum/blade
                swather.SwathSingleCell(false, PassType.Front, cellPass.CellE_m, cellPass.CellN_m, VOLVO_EARTHWORKS_GRID_CELL_SIZE, cellPass);

                processor.ProcessedEpochCount = swather.ProcessedEpochNumber;
            });

            return(TAGReadResult.NoError);
        }