From 269d204b18bff2111ea6f68d393a1e5ab299c892 Mon Sep 17 00:00:00 2001 From: Tom Willemsen Date: Mon, 12 Oct 2026 10:12:45 +0100 Subject: [PATCH 1/2] Add GPS start/stop timestamps to run start/stop, alongside computer/NTP timestamps --- schemas/6s4t_run_stop.fbs | 3 ++- schemas/pl72_run_start.fbs | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/schemas/6s4t_run_stop.fbs b/schemas/6s4t_run_stop.fbs index a87012d..7dd9045 100644 --- a/schemas/6s4t_run_stop.fbs +++ b/schemas/6s4t_run_stop.fbs @@ -10,11 +10,12 @@ file_identifier "6s4t"; table RunStop { // *Mantid* // *File Writer* // *Description* - stop_time : uint64; // Required // Required // milliseconds since Unix epoch (1 Jan 1970). When set to 0, will trigger a "stop NOW" code path in the file writer. + stop_time : uint64; // Required // Required // milliseconds since Unix epoch (1 Jan 1970), according to an NTP-synchronised computer clock. When set to 0, will trigger a "stop NOW" code path in the file writer. run_name : string; // Required // Unused // Name for the run, must match corresponding field in RunStart job_id : string; // Unused // Required // Uuid of the job that is to get a new stop time. service_id : string; // Unused // Optional // The identifier for the instance of the file-writer that should handle this command command_id : string; // Unused // Required // Command uuid for uniquely identifying the stop command. + gps_stop_time : uint64 = null; // Unused // Required // milliseconds since Unix epoch (1 Jan 1970), according to the GPS clock used to timestamp events. } root_type RunStop; diff --git a/schemas/pl72_run_start.fbs b/schemas/pl72_run_start.fbs index 42e22b9..902b849 100644 --- a/schemas/pl72_run_start.fbs +++ b/schemas/pl72_run_start.fbs @@ -12,8 +12,8 @@ include "df12_det_spec_map.fbs"; file_identifier "pl72"; table RunStart { // *Mantid* // *File Writer* // *Description* - start_time : uint64; // Required // Required // milliseconds since Unix epoch (1 Jan 1970) - stop_time : uint64; // Unused // Optional // milliseconds since Unix epoch (1 Jan 1970), optional, can send a RunStop instead + start_time : uint64; // Required // Required // milliseconds since Unix epoch (1 Jan 1970), according to an NTP-synchronised computer clock + stop_time : uint64; // Unused // Optional // milliseconds since Unix epoch (1 Jan 1970), according to an NTP-synchronised computer clock. Optional, can send a RunStop instead run_name : string; // Required // Unused // Name for the run, used as workspace name by Mantid instrument_name : string; // Required // Unused // Name of the instrument, only required by Mantid nexus_structure : string; // Optional // Required // JSON description of NeXus file (See https://github.com/ess-dmsc/kafka-to-nexus/ for detail) @@ -28,6 +28,8 @@ table RunStart { // *Mantid* // *File Wr detector_spectrum_map: SpectraDetectorMapping; // Optional // Unused // Map spectrum numbers in the event messages to detector IDs in the instrument definition (optional, for ISIS only) metadata : string; // Unused // Optional // Holds a JSON string with (static) metadata about the measurement. E.g. proposal id. control_topic : string; // Unused // Optional // Topic on which the File Writer will listen for further commands and publish status messages when started from a pool + gps_start_time : uint64 = null; // Unused // Required // milliseconds since Unix epoch (1 Jan 1970), according to the GPS clock used to timestamp events. + gps_stop_time : uint64 = null; // Unused // Required // milliseconds since Unix epoch (1 Jan 1970), according to the GPS clock used to timestamp events. } root_type RunStart; From 60c121d6d397ad246a065818873b4f21f2926f12 Mon Sep 17 00:00:00 2001 From: Tom Willemsen Date: Mon, 12 Oct 2026 10:29:54 +0100 Subject: [PATCH 2/2] Update rust/python bindings for gps start/stop times in run start/stop --- .../fbschemas/run_start_pl72/RunStart.py | 117 +++++++++++++++--- .../fbschemas/run_stop_6s4t/RunStop.py | 60 +++++++-- .../streaming_data_types/run_start_pl72.py | 18 +++ .../src/streaming_data_types/run_stop_6s4t.py | 25 ++-- python/tests/test_6s4t.py | 2 + python/tests/test_pl72.py | 4 + .../flatbuffers_generated/6s4t_run_stop.rs | 17 +++ .../flatbuffers_generated/pl72_run_start.rs | 34 +++++ schemas/6s4t_run_stop.fbs | 2 +- schemas/pl72_run_start.fbs | 4 +- 10 files changed, 247 insertions(+), 36 deletions(-) diff --git a/python/src/streaming_data_types/fbschemas/run_start_pl72/RunStart.py b/python/src/streaming_data_types/fbschemas/run_start_pl72/RunStart.py index d6e86fd..d48bdc4 100644 --- a/python/src/streaming_data_types/fbschemas/run_start_pl72/RunStart.py +++ b/python/src/streaming_data_types/fbschemas/run_start_pl72/RunStart.py @@ -12,16 +12,21 @@ class RunStart(object): __slots__ = ["_tab"] @classmethod - def GetRootAsRunStart(cls, buf, offset): + def GetRootAs(cls, buf, offset=0): n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) x = RunStart() x.Init(buf, n + offset) return x + @classmethod + def GetRootAsRunStart(cls, buf, offset=0): + """This method is deprecated. Please switch to GetRootAs.""" + return cls.GetRootAs(buf, offset) + @classmethod def RunStartBufferHasIdentifier(cls, buf, offset, size_prefixed=False): return flatbuffers.util.BufferHasIdentifier( - buf, offset, b"\x70\x6C\x37\x32", size_prefixed=size_prefixed + buf, offset, b"\x70\x6c\x37\x32", size_prefixed=size_prefixed ) # RunStart @@ -32,18 +37,14 @@ def Init(self, buf, pos): def StartTime(self): o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) if o != 0: - return self._tab.Get( - flatbuffers.number_types.Uint64Flags, o + self._tab.Pos - ) + return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos) return 0 # RunStart def StopTime(self): o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) if o != 0: - return self._tab.Get( - flatbuffers.number_types.Uint64Flags, o + self._tab.Pos - ) + return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos) return 0 # RunStart @@ -99,9 +100,7 @@ def Filename(self): def NPeriods(self): o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22)) if o != 0: - return self._tab.Get( - flatbuffers.number_types.Uint32Flags, o + self._tab.Pos - ) + return self._tab.Get(flatbuffers.number_types.Uint32Flags, o + self._tab.Pos) return 1 # RunStart @@ -130,41 +129,81 @@ def ControlTopic(self): return self._tab.String(o + self._tab.Pos) return None + # RunStart + def GpsStartTime(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30)) + if o != 0: + return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos) + return None + + # RunStart + def GpsStopTime(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(32)) + if o != 0: + return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos) + return None + def RunStartStart(builder): - builder.StartObject(13) + builder.StartObject(15) + + +def Start(builder): + RunStartStart(builder) def RunStartAddStartTime(builder, startTime): builder.PrependUint64Slot(0, startTime, 0) +def AddStartTime(builder, startTime): + RunStartAddStartTime(builder, startTime) + + def RunStartAddStopTime(builder, stopTime): builder.PrependUint64Slot(1, stopTime, 0) +def AddStopTime(builder, stopTime): + RunStartAddStopTime(builder, stopTime) + + def RunStartAddRunName(builder, runName): builder.PrependUOffsetTRelativeSlot( 2, flatbuffers.number_types.UOffsetTFlags.py_type(runName), 0 ) +def AddRunName(builder, runName): + RunStartAddRunName(builder, runName) + + def RunStartAddInstrumentName(builder, instrumentName): builder.PrependUOffsetTRelativeSlot( 3, flatbuffers.number_types.UOffsetTFlags.py_type(instrumentName), 0 ) +def AddInstrumentName(builder, instrumentName): + RunStartAddInstrumentName(builder, instrumentName) + + def RunStartAddNexusStructure(builder, nexusStructure): builder.PrependUOffsetTRelativeSlot( 4, flatbuffers.number_types.UOffsetTFlags.py_type(nexusStructure), 0 ) +def AddNexusStructure(builder, nexusStructure): + RunStartAddNexusStructure(builder, nexusStructure) + + def RunStartAddJobId(builder, jobId): - builder.PrependUOffsetTRelativeSlot( - 5, flatbuffers.number_types.UOffsetTFlags.py_type(jobId), 0 - ) + builder.PrependUOffsetTRelativeSlot(5, flatbuffers.number_types.UOffsetTFlags.py_type(jobId), 0) + + +def AddJobId(builder, jobId): + RunStartAddJobId(builder, jobId) def RunStartAddBroker(builder, broker): @@ -173,39 +212,87 @@ def RunStartAddBroker(builder, broker): ) +def AddBroker(builder, broker): + RunStartAddBroker(builder, broker) + + def RunStartAddServiceId(builder, serviceId): builder.PrependUOffsetTRelativeSlot( 7, flatbuffers.number_types.UOffsetTFlags.py_type(serviceId), 0 ) +def AddServiceId(builder, serviceId): + RunStartAddServiceId(builder, serviceId) + + def RunStartAddFilename(builder, filename): builder.PrependUOffsetTRelativeSlot( 8, flatbuffers.number_types.UOffsetTFlags.py_type(filename), 0 ) +def AddFilename(builder, filename): + RunStartAddFilename(builder, filename) + + def RunStartAddNPeriods(builder, nPeriods): builder.PrependUint32Slot(9, nPeriods, 1) +def AddNPeriods(builder, nPeriods): + RunStartAddNPeriods(builder, nPeriods) + + def RunStartAddDetectorSpectrumMap(builder, detectorSpectrumMap): builder.PrependUOffsetTRelativeSlot( 10, flatbuffers.number_types.UOffsetTFlags.py_type(detectorSpectrumMap), 0 ) +def AddDetectorSpectrumMap(builder, detectorSpectrumMap): + RunStartAddDetectorSpectrumMap(builder, detectorSpectrumMap) + + def RunStartAddMetadata(builder, metadata): builder.PrependUOffsetTRelativeSlot( 11, flatbuffers.number_types.UOffsetTFlags.py_type(metadata), 0 ) +def AddMetadata(builder, metadata): + RunStartAddMetadata(builder, metadata) + + def RunStartAddControlTopic(builder, controlTopic): builder.PrependUOffsetTRelativeSlot( 12, flatbuffers.number_types.UOffsetTFlags.py_type(controlTopic), 0 ) +def AddControlTopic(builder, controlTopic): + RunStartAddControlTopic(builder, controlTopic) + + +def RunStartAddGpsStartTime(builder, gpsStartTime): + builder.PrependUint64Slot(13, gpsStartTime, None) + + +def AddGpsStartTime(builder, gpsStartTime): + RunStartAddGpsStartTime(builder, gpsStartTime) + + +def RunStartAddGpsStopTime(builder, gpsStopTime): + builder.PrependUint64Slot(14, gpsStopTime, None) + + +def AddGpsStopTime(builder, gpsStopTime): + RunStartAddGpsStopTime(builder, gpsStopTime) + + def RunStartEnd(builder): return builder.EndObject() + + +def End(builder): + return RunStartEnd(builder) diff --git a/python/src/streaming_data_types/fbschemas/run_stop_6s4t/RunStop.py b/python/src/streaming_data_types/fbschemas/run_stop_6s4t/RunStop.py index 55faf97..e3dd781 100644 --- a/python/src/streaming_data_types/fbschemas/run_stop_6s4t/RunStop.py +++ b/python/src/streaming_data_types/fbschemas/run_stop_6s4t/RunStop.py @@ -12,12 +12,17 @@ class RunStop(object): __slots__ = ["_tab"] @classmethod - def GetRootAsRunStop(cls, buf, offset): + def GetRootAs(cls, buf, offset=0): n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) x = RunStop() x.Init(buf, n + offset) return x + @classmethod + def GetRootAsRunStop(cls, buf, offset=0): + """This method is deprecated. Please switch to GetRootAs.""" + return cls.GetRootAs(buf, offset) + @classmethod def RunStopBufferHasIdentifier(cls, buf, offset, size_prefixed=False): return flatbuffers.util.BufferHasIdentifier( @@ -32,9 +37,7 @@ def Init(self, buf, pos): def StopTime(self): o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) if o != 0: - return self._tab.Get( - flatbuffers.number_types.Uint64Flags, o + self._tab.Pos - ) + return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos) return 0 # RunStop @@ -65,25 +68,46 @@ def CommandId(self): return self._tab.String(o + self._tab.Pos) return None + # RunStop + def GpsStopTime(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14)) + if o != 0: + return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos) + return None + def RunStopStart(builder): - builder.StartObject(5) + builder.StartObject(6) + + +def Start(builder): + RunStopStart(builder) def RunStopAddStopTime(builder, stopTime): builder.PrependUint64Slot(0, stopTime, 0) +def AddStopTime(builder, stopTime): + RunStopAddStopTime(builder, stopTime) + + def RunStopAddRunName(builder, runName): builder.PrependUOffsetTRelativeSlot( 1, flatbuffers.number_types.UOffsetTFlags.py_type(runName), 0 ) +def AddRunName(builder, runName): + RunStopAddRunName(builder, runName) + + def RunStopAddJobId(builder, jobId): - builder.PrependUOffsetTRelativeSlot( - 2, flatbuffers.number_types.UOffsetTFlags.py_type(jobId), 0 - ) + builder.PrependUOffsetTRelativeSlot(2, flatbuffers.number_types.UOffsetTFlags.py_type(jobId), 0) + + +def AddJobId(builder, jobId): + RunStopAddJobId(builder, jobId) def RunStopAddServiceId(builder, serviceId): @@ -92,11 +116,31 @@ def RunStopAddServiceId(builder, serviceId): ) +def AddServiceId(builder, serviceId): + RunStopAddServiceId(builder, serviceId) + + def RunStopAddCommandId(builder, commandId): builder.PrependUOffsetTRelativeSlot( 4, flatbuffers.number_types.UOffsetTFlags.py_type(commandId), 0 ) +def AddCommandId(builder, commandId): + RunStopAddCommandId(builder, commandId) + + +def RunStopAddGpsStopTime(builder, gpsStopTime): + builder.PrependUint64Slot(5, gpsStopTime, None) + + +def AddGpsStopTime(builder, gpsStopTime): + RunStopAddGpsStopTime(builder, gpsStopTime) + + def RunStopEnd(builder): return builder.EndObject() + + +def End(builder): + return RunStopEnd(builder) diff --git a/python/src/streaming_data_types/run_start_pl72.py b/python/src/streaming_data_types/run_start_pl72.py index bcc50ab..7a0763f 100644 --- a/python/src/streaming_data_types/run_start_pl72.py +++ b/python/src/streaming_data_types/run_start_pl72.py @@ -38,6 +38,8 @@ def serialise_pl72( metadata: str = "{}", detector_spectrum_map: Optional[DetectorSpectrumMap] = None, control_topic: str = "", + gps_start_time: Union[int, datetime, None] = None, + gps_stop_time: Union[int, datetime, None] = None, ) -> bytes: builder = flatbuffers.Builder(512) builder.ForceDefaults(True) @@ -102,6 +104,16 @@ def serialise_pl72( RunStart.RunStartAddDetectorSpectrumMap(builder, detector_spectrum_map_offset) RunStart.RunStartAddControlTopic(builder, control_topic_offset) + if gps_start_time is not None: + if type(gps_start_time) is datetime: + gps_start_time = int(gps_start_time.timestamp() * 1_000_000_000) + RunStart.RunStartAddGpsStartTime(builder, gps_start_time) + + if gps_stop_time is not None: + if type(gps_stop_time) is datetime: + gps_stop_time = int(gps_stop_time.timestamp() * 1_000_000_000) + RunStart.RunStartAddGpsStopTime(builder, gps_stop_time) + run_start_message = RunStart.RunStartEnd(builder) builder.Finish(run_start_message, file_identifier=FILE_IDENTIFIER) @@ -121,6 +133,8 @@ class RunStartInfo(NamedTuple): metadata: str = "" detector_spectrum_map: Optional[DetectorSpectrumMap] = None control_topic: str = "" + gps_start_time: Union[int, None] = None + gps_stop_time: Union[int, None] = None def deserialise_pl72(buffer: Union[bytearray, bytes]) -> RunStartInfo: @@ -136,6 +150,8 @@ def deserialise_pl72(buffer: Union[bytearray, bytes]) -> RunStartInfo: run_name = run_start.RunName() if run_start.RunName() else b"" metadata = run_start.Metadata() if run_start.Metadata() else b"" control_topic = run_start.ControlTopic() if run_start.ControlTopic() else b"" + gps_start_time = run_start.GpsStartTime() + gps_stop_time = run_start.GpsStopTime() detector_spectrum_map = None det_spec_map_buf = run_start.DetectorSpectrumMap() @@ -159,4 +175,6 @@ def deserialise_pl72(buffer: Union[bytearray, bytes]) -> RunStartInfo: metadata=metadata.decode(), detector_spectrum_map=detector_spectrum_map, control_topic=control_topic.decode(), + gps_start_time=gps_start_time, + gps_stop_time=gps_stop_time, ) diff --git a/python/src/streaming_data_types/run_stop_6s4t.py b/python/src/streaming_data_types/run_stop_6s4t.py index fadf4ef..326d9ef 100644 --- a/python/src/streaming_data_types/run_stop_6s4t.py +++ b/python/src/streaming_data_types/run_stop_6s4t.py @@ -15,6 +15,7 @@ def serialise_6s4t( service_id: str = "", command_id: str = "", stop_time: Union[int, datetime, None] = None, + gps_stop_time: Union[int, datetime, None] = None, ) -> bytes: builder = flatbuffers.Builder(500) builder.ForceDefaults(True) @@ -39,22 +40,24 @@ def serialise_6s4t( RunStop.RunStopAddStopTime(builder, stop_time) RunStop.RunStopAddCommandId(builder, command_id_offset) + if gps_stop_time is not None: + if type(gps_stop_time) is datetime: + gps_stop_time = int(gps_stop_time.timestamp() * 1_000_000_000) + RunStop.RunStopAddGpsStopTime(builder, gps_stop_time) + run_stop_message = RunStop.RunStopEnd(builder) builder.Finish(run_stop_message, file_identifier=FILE_IDENTIFIER) return bytes(builder.Output()) -RunStopInfo = NamedTuple( - "RunStopInfo", - ( - ("stop_time", int), - ("run_name", str), - ("job_id", str), - ("service_id", str), - ("command_id", str), - ), -) +class RunStopInfo(NamedTuple): + stop_time: int + run_name: str + job_id: str + service_id: str + command_id: str + gps_stop_time: int | None def deserialise_6s4t(buffer: Union[bytearray, bytes]) -> RunStopInfo: @@ -66,6 +69,7 @@ def deserialise_6s4t(buffer: Union[bytearray, bytes]) -> RunStopInfo: run_name = run_stop.RunName() if run_stop.RunName() else b"" stop_time = run_stop.StopTime() command_id = run_stop.CommandId() + gps_stop_time = run_stop.GpsStopTime() return RunStopInfo( stop_time=stop_time, @@ -73,4 +77,5 @@ def deserialise_6s4t(buffer: Union[bytearray, bytes]) -> RunStopInfo: job_id=job_id.decode(), service_id=service_id.decode(), command_id=command_id.decode(), + gps_stop_time=gps_stop_time, ) diff --git a/python/tests/test_6s4t.py b/python/tests/test_6s4t.py index 772bb61..a5a39dd 100644 --- a/python/tests/test_6s4t.py +++ b/python/tests/test_6s4t.py @@ -12,6 +12,7 @@ class TestSerialisation6s4t: "run_name": "test_run", "service_id": "filewriter1", "command_id": "some command id", + "gps_stop_time": 123456789, } def test_serialises_and_deserialises_6s4t_message_correctly(self): @@ -23,6 +24,7 @@ def test_serialises_and_deserialises_6s4t_message_correctly(self): assert deserialised_tuple.run_name == self.original_entry["run_name"] assert deserialised_tuple.service_id == self.original_entry["service_id"] assert deserialised_tuple.command_id == self.original_entry["command_id"] + assert deserialised_tuple.gps_stop_time == self.original_entry["gps_stop_time"] def test_if_buffer_has_wrong_id_then_throws(self): buf = serialise_6s4t(**self.original_entry) diff --git a/python/tests/test_pl72.py b/python/tests/test_pl72.py index eab7d78..048ac0f 100644 --- a/python/tests/test_pl72.py +++ b/python/tests/test_pl72.py @@ -26,6 +26,8 @@ class TestSerialisationPl72: np.array([4, 5, 6]), np.array([0, 1, 2]), 3 ), "control_topic": "some_topic_name", + "gps_start_time": 123456789, + "gps_stop_time": 9876543210, } def test_serialises_and_deserialises_pl72_message_correctly(self): @@ -60,6 +62,8 @@ def test_serialises_and_deserialises_pl72_message_correctly(self): self.original_entry["detector_spectrum_map"].detector_ids, ) assert deserialised_tuple.control_topic == self.original_entry["control_topic"] + assert deserialised_tuple.gps_start_time == self.original_entry["gps_start_time"] + assert deserialised_tuple.gps_stop_time == self.original_entry["gps_stop_time"] def test_if_buffer_has_wrong_id_then_throws(self): buf = serialise_pl72(**self.original_entry) diff --git a/rust/src/flatbuffers_generated/6s4t_run_stop.rs b/rust/src/flatbuffers_generated/6s4t_run_stop.rs index 506c531..1bcb9e6 100644 --- a/rust/src/flatbuffers_generated/6s4t_run_stop.rs +++ b/rust/src/flatbuffers_generated/6s4t_run_stop.rs @@ -24,6 +24,7 @@ impl<'a> RunStop<'a> { pub const VT_JOB_ID: ::flatbuffers::VOffsetT = 8; pub const VT_SERVICE_ID: ::flatbuffers::VOffsetT = 10; pub const VT_COMMAND_ID: ::flatbuffers::VOffsetT = 12; + pub const VT_GPS_STOP_TIME: ::flatbuffers::VOffsetT = 14; #[inline] pub unsafe fn init_from_table(table: ::flatbuffers::Table<'a>) -> Self { @@ -35,6 +36,7 @@ impl<'a> RunStop<'a> { args: &'args RunStopArgs<'args> ) -> ::flatbuffers::WIPOffset> { let mut builder = RunStopBuilder::new(_fbb); + if let Some(x) = args.gps_stop_time { builder.add_gps_stop_time(x); } builder.add_stop_time(args.stop_time); if let Some(x) = args.command_id { builder.add_command_id(x); } if let Some(x) = args.service_id { builder.add_service_id(x); } @@ -79,6 +81,13 @@ impl<'a> RunStop<'a> { // which contains a valid value in this slot unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<&str>>(RunStop::VT_COMMAND_ID, None)} } + #[inline] + pub fn gps_stop_time(&self) -> Option { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(RunStop::VT_GPS_STOP_TIME, None)} + } } impl ::flatbuffers::Verifiable for RunStop<'_> { @@ -92,6 +101,7 @@ impl ::flatbuffers::Verifiable for RunStop<'_> { .visit_field::<::flatbuffers::ForwardsUOffset<&str>>("job_id", Self::VT_JOB_ID, false)? .visit_field::<::flatbuffers::ForwardsUOffset<&str>>("service_id", Self::VT_SERVICE_ID, false)? .visit_field::<::flatbuffers::ForwardsUOffset<&str>>("command_id", Self::VT_COMMAND_ID, false)? + .visit_field::("gps_stop_time", Self::VT_GPS_STOP_TIME, false)? .finish(); Ok(()) } @@ -102,6 +112,7 @@ pub struct RunStopArgs<'a> { pub job_id: Option<::flatbuffers::WIPOffset<&'a str>>, pub service_id: Option<::flatbuffers::WIPOffset<&'a str>>, pub command_id: Option<::flatbuffers::WIPOffset<&'a str>>, + pub gps_stop_time: Option, } impl<'a> Default for RunStopArgs<'a> { #[inline] @@ -112,6 +123,7 @@ impl<'a> Default for RunStopArgs<'a> { job_id: None, service_id: None, command_id: None, + gps_stop_time: None, } } } @@ -142,6 +154,10 @@ impl<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> RunStopBuilder<'a, 'b, A> { self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(RunStop::VT_COMMAND_ID, command_id); } #[inline] + pub fn add_gps_stop_time(&mut self, gps_stop_time: u64) { + self.fbb_.push_slot_always::(RunStop::VT_GPS_STOP_TIME, gps_stop_time); + } + #[inline] pub fn new(_fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>) -> RunStopBuilder<'a, 'b, A> { let start = _fbb.start_table(); RunStopBuilder { @@ -164,6 +180,7 @@ impl ::core::fmt::Debug for RunStop<'_> { ds.field("job_id", &self.job_id()); ds.field("service_id", &self.service_id()); ds.field("command_id", &self.command_id()); + ds.field("gps_stop_time", &self.gps_stop_time()); ds.finish() } } diff --git a/rust/src/flatbuffers_generated/pl72_run_start.rs b/rust/src/flatbuffers_generated/pl72_run_start.rs index 412df29..be4f82d 100644 --- a/rust/src/flatbuffers_generated/pl72_run_start.rs +++ b/rust/src/flatbuffers_generated/pl72_run_start.rs @@ -162,6 +162,8 @@ impl<'a> RunStart<'a> { pub const VT_DETECTOR_SPECTRUM_MAP: ::flatbuffers::VOffsetT = 24; pub const VT_METADATA: ::flatbuffers::VOffsetT = 26; pub const VT_CONTROL_TOPIC: ::flatbuffers::VOffsetT = 28; + pub const VT_GPS_START_TIME: ::flatbuffers::VOffsetT = 30; + pub const VT_GPS_STOP_TIME: ::flatbuffers::VOffsetT = 32; #[inline] pub unsafe fn init_from_table(table: ::flatbuffers::Table<'a>) -> Self { @@ -173,6 +175,8 @@ impl<'a> RunStart<'a> { args: &'args RunStartArgs<'args> ) -> ::flatbuffers::WIPOffset> { let mut builder = RunStartBuilder::new(_fbb); + if let Some(x) = args.gps_stop_time { builder.add_gps_stop_time(x); } + if let Some(x) = args.gps_start_time { builder.add_gps_start_time(x); } builder.add_stop_time(args.stop_time); builder.add_start_time(args.start_time); if let Some(x) = args.control_topic { builder.add_control_topic(x); } @@ -281,6 +285,20 @@ impl<'a> RunStart<'a> { // which contains a valid value in this slot unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<&str>>(RunStart::VT_CONTROL_TOPIC, None)} } + #[inline] + pub fn gps_start_time(&self) -> Option { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(RunStart::VT_GPS_START_TIME, None)} + } + #[inline] + pub fn gps_stop_time(&self) -> Option { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(RunStart::VT_GPS_STOP_TIME, None)} + } } impl ::flatbuffers::Verifiable for RunStart<'_> { @@ -302,6 +320,8 @@ impl ::flatbuffers::Verifiable for RunStart<'_> { .visit_field::<::flatbuffers::ForwardsUOffset>("detector_spectrum_map", Self::VT_DETECTOR_SPECTRUM_MAP, false)? .visit_field::<::flatbuffers::ForwardsUOffset<&str>>("metadata", Self::VT_METADATA, false)? .visit_field::<::flatbuffers::ForwardsUOffset<&str>>("control_topic", Self::VT_CONTROL_TOPIC, false)? + .visit_field::("gps_start_time", Self::VT_GPS_START_TIME, false)? + .visit_field::("gps_stop_time", Self::VT_GPS_STOP_TIME, false)? .finish(); Ok(()) } @@ -320,6 +340,8 @@ pub struct RunStartArgs<'a> { pub detector_spectrum_map: Option<::flatbuffers::WIPOffset>>, pub metadata: Option<::flatbuffers::WIPOffset<&'a str>>, pub control_topic: Option<::flatbuffers::WIPOffset<&'a str>>, + pub gps_start_time: Option, + pub gps_stop_time: Option, } impl<'a> Default for RunStartArgs<'a> { #[inline] @@ -338,6 +360,8 @@ impl<'a> Default for RunStartArgs<'a> { detector_spectrum_map: None, metadata: None, control_topic: None, + gps_start_time: None, + gps_stop_time: None, } } } @@ -400,6 +424,14 @@ impl<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> RunStartBuilder<'a, 'b, A> { self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(RunStart::VT_CONTROL_TOPIC, control_topic); } #[inline] + pub fn add_gps_start_time(&mut self, gps_start_time: u64) { + self.fbb_.push_slot_always::(RunStart::VT_GPS_START_TIME, gps_start_time); + } + #[inline] + pub fn add_gps_stop_time(&mut self, gps_stop_time: u64) { + self.fbb_.push_slot_always::(RunStart::VT_GPS_STOP_TIME, gps_stop_time); + } + #[inline] pub fn new(_fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>) -> RunStartBuilder<'a, 'b, A> { let start = _fbb.start_table(); RunStartBuilder { @@ -430,6 +462,8 @@ impl ::core::fmt::Debug for RunStart<'_> { ds.field("detector_spectrum_map", &self.detector_spectrum_map()); ds.field("metadata", &self.metadata()); ds.field("control_topic", &self.control_topic()); + ds.field("gps_start_time", &self.gps_start_time()); + ds.field("gps_stop_time", &self.gps_stop_time()); ds.finish() } } diff --git a/schemas/6s4t_run_stop.fbs b/schemas/6s4t_run_stop.fbs index 7dd9045..c8b5b43 100644 --- a/schemas/6s4t_run_stop.fbs +++ b/schemas/6s4t_run_stop.fbs @@ -15,7 +15,7 @@ table RunStop { // *Mantid* // *File Writer* // *Description* job_id : string; // Unused // Required // Uuid of the job that is to get a new stop time. service_id : string; // Unused // Optional // The identifier for the instance of the file-writer that should handle this command command_id : string; // Unused // Required // Command uuid for uniquely identifying the stop command. - gps_stop_time : uint64 = null; // Unused // Required // milliseconds since Unix epoch (1 Jan 1970), according to the GPS clock used to timestamp events. + gps_stop_time : uint64 = null; // Unused // Required // nanoseconds since Unix epoch (1 Jan 1970), according to the GPS clock used to timestamp events. } root_type RunStop; diff --git a/schemas/pl72_run_start.fbs b/schemas/pl72_run_start.fbs index 902b849..c8f6e20 100644 --- a/schemas/pl72_run_start.fbs +++ b/schemas/pl72_run_start.fbs @@ -28,8 +28,8 @@ table RunStart { // *Mantid* // *File Wr detector_spectrum_map: SpectraDetectorMapping; // Optional // Unused // Map spectrum numbers in the event messages to detector IDs in the instrument definition (optional, for ISIS only) metadata : string; // Unused // Optional // Holds a JSON string with (static) metadata about the measurement. E.g. proposal id. control_topic : string; // Unused // Optional // Topic on which the File Writer will listen for further commands and publish status messages when started from a pool - gps_start_time : uint64 = null; // Unused // Required // milliseconds since Unix epoch (1 Jan 1970), according to the GPS clock used to timestamp events. - gps_stop_time : uint64 = null; // Unused // Required // milliseconds since Unix epoch (1 Jan 1970), according to the GPS clock used to timestamp events. + gps_start_time : uint64 = null; // Unused // Required // nanoseconds since Unix epoch (1 Jan 1970), according to the GPS clock used to timestamp events. + gps_stop_time : uint64 = null; // Unused // Required // nanoseconds since Unix epoch (1 Jan 1970), according to the GPS clock used to timestamp events. } root_type RunStart;